Professorer och Python

Hej, det är jag.

Professor Spelet

När jag packade mina saker som jag ville ha med mig till Linköping snubblade jag över ett spel som varit i familjens ägo sedan jag var liten. Spelet i fråga kallas ”Professor Spelet” och är ett pusselspel av hög svårighetsgrad. Jag tänkte att det vore ett perfekt spel att ta med ner, något som kan hålla mig varm om ensamma kvällar, kokande av frustration då det är ett ganska omöjligt pussel om man försöker lösa det på det konventionella sättet. Låt mig visa med hjälp av några bilder hur pusslet ska lösas:

Framsidan på karotngen till Professor Spelet

Här ser vi framsidan av spelets kartong med ett förslag, visserligen inkorrekt, på hur man kan placera de 16 brickorna som följer med spelet.

Varje kort består av två överkroppar och två par ben, varje del har en av färgerna blå, brun, grön och lila. Varje professor är utsmyckad med ett extremt självbelåtet flin då de vet att de kommer driva dig till vansinne om du försöker dig på att lösa deras pussel.

Varje kort består av två överkroppar och två par ben, varje del har en av färgerna blå, brun, grön och lila. Varje professor är utsmyckad med ett extremt självbelåtet flin då de vet att de kommer driva dig till vansinne om du försöker dig på att lösa deras pussel.

Sedär, grön överkropp passar med gröna ben, bra jobbat. Nu gäller det bara att passa ihop de återstående 14 korten på motsvarande sätt i en 4×4 formation.

Sedär, grön överkropp passar med gröna ben, bra jobbat. Nu gäller det bara att passa ihop de återstående 14 korten på motsvarande sätt i en 4×4 formation.

Jag tänkte att jag skulle lösa pusslet med hjälp av lite mysig Python-programmering, men innan kodningen tar fart kan det vara bra att komma på (en början till) receptet till framgång.

Algoritmen

Eftersom en dator kan göra vissa uträkningar mycket snabbt formulerade jag en lösning på pusslet som helt enkelt provar att lägga ut kort så långt det går och om det inte går får man backtracka. I detalj:

  1. Lägg ett kort ”längst upp till vänster”.
  2. Gå igenom resterande kort och se om något passar på nästa position. Nästa position är i regel till höger om kortet du just la ut MEN om man har en rad av kort som är fyra till antalet lägger man inte nästa kort till höger utan istället läggs nästa kort under det vänstra kortet på den lägsta raden. ”Passar” gör korten om de kroppsdelar som sätts ihop har samma färg men inte är av samma typ. (Man kan ju inte ha en professor som bara är två par ben, även om det säkert passar bra i andra spel.)
  3. Om inget av dina resterande kort passar på nästa position så säger vi att det kortet du just la ut var ”FEL” och det tas bort och man får prova med något annat kort man har på handen.
  4. Till slut kommer du hamna i ett av två lägen. Antingen lyckas du lägga ett kort längst ner till höger, då har vi lyckats! Det andra utfallet är om vi inte kan lägga ut något av de 16 korten på platsen högst upp till vänster, dvs alla kort har markerats som ”FEL” och vi har tokfailat.

Det där var en något förenklad bild av hur jag valt att lösa pusslet, till exempel nämner jag inget om att man kan (såklart) rotera korten och få nya möjligheter till att matcha korten på hand med de som ligger på bordet. Men vet ni vad, det var tillräckligt svårt att ge beskrivningen ovan, om jag fortsätter kommer det nog tyvärr resultera i att både jag och mina fina läsare får en fruktansvärd huvudvärk.

Innan jag presenterar koden vill jag peka lite extra på några saker med programmering i allmänhet och kanske Python i synnerhet, nämligen dundermysiga dictionaries och vad man kan göra med dem.

Dundermysiga Dictionaries

På svenska kan man kalla en dictionary för en associativ lista, på svenska som någon förstår kan man kalla en associativ lista för en säck med objekt där varje objekt också är ett par objekt där den ena delen är ett nyckelord som man kan använda för att få fram värdet på den andra delen. Hmm, ingen förstod nog det där sista heller.. Ojoj, det är klurigt att förklara saker i programmering, jag försöker visa det med några exempel istället. Och jag kanske väljer att kalla en dictionary för en ordlista i fortsättningen, genialiskt. :)

Exempel: Familjen Andersson har ett system där varje famlijemedlem får skriva upp en matvara och tillsammans utgör varje medlems matvara veckans inköpslista. Familjen Andersson är pappa Rickard, mamma Cecilia och barnen Johan, Mikael, Jessica samt Linn. När man vet vad man vill ha lägger man till informationen i den fina ordlistan och jag ska visa er hur det ser ut i Pythonkod.

>>> { }

Såhär ser ordlistan ut när den är tom ‘{‘ (vänster curlingparentes) är början och ‘}’ (höger dito) markerar slutet, tråkigt =/

>>> {"Johan": "Rödbetor"}

Hurra, Johan har lagt in att han är sugen på rödbetor, kanske har han en pakt med övriga i familjen att det ska ätas pytt-i-panna. Här ser vi alltså ett objekt i ordlistan, ”Johan” utgör nyckeln och ”Rödbetor” är värdet.

>>> {"Johan": "Rödbetor", "Jessica": "Polarbröd","Rickard": "Havrefras",
     "Linn": "Jordnötssmör", "Cecilia": "Sötmandel"}

Johans drömmar om pytt-i-panna tycks ha slagits i spillror. Men nu har vi iaf en ordlista med fem nycklar som har tillhörande fem mumsiga värden (matvarorna). Vi gör en tilldelning och sparar vår ordlista i en variabel vi kallar för matkassen:

matkassen = {"Johan": "Rödbetor", "Jessica": "Polarbröd",
             "Rickard": "Havrefras", "Linn": "Jordnötssmör",
             "Cecilia": "Sötmandel"}

Nu vill pappa Rickard samla ihop allt detta till en behändig inköpslista, det gör han med en loop och nycklar (namnen) som gör en uppslagning i matkassen för att ta reda på värdet till nyckeln, det vill säga vad varje person har önskat sig.

inköpslista = [] # Japp, inköpslistan är tom i början, quelle surprise.
for namn in ["Rickard", "Cecilia","Johan", "Mikael", "Jessica", "Linn"]:
    inköpslista.append( matkassen.get(namn) )

När Rickard går igenom inköpslistan ser han att det bara finns fem stycken matvaror, fast de är sex stycken i familjen. Efter ett mycket välorganiserat familjeråd kommer det fram att Mikael inte önskat sig någon matvara då han istället för att äta tänker spendera den kommande veckan med att skriva en dikt om den svarta kaninen han hittade när han var på urban exploration i Varbergs största bunker, Bergabunkern. Pappa Rickard har en lösning på problemet med inköslistan och gör en ny loop:

inköpslista = [] # Töm inköpslistan igen, tan terrible.
for namn in ["Rickard", "Cecilia","Johan", "Mikael", "Jessica", "Linn"]:
    matkassen.setdefault(namn, "Mera havrefras")
    inköpslista.append( matkassen.get(namn) )

Det funktionen setdefault gör är att om en nyckel inte finns i en ordlista så skapas den med ett valfritt värde, i exemplet ovan ”Mera havrefras”. Havrefras har trots allt en tendens att ta slut mycket fortare än man vill. Nu kommer Rickard alltid att ha en fullständig inköpslista varje gång även om någon familjemedlem missar att önska, den önskan blir bara ersatt med ”Mera havrefras”. Men vänta, Linn som är 1337 tar en titt på koden och säger ”Pappa, din kod kan optimeras, låt mig snygga till den här spagettiröran lite”:

inköpslista = [] # Töm inköpslistan, ich liebe es.
for namn in ["Rickard", "Cecilia","Johan", "Mikael", "Jessica", "Linn"]:
    inköpslista.append( matkassen.get(namn, "Mera havrefras") )

Ni förstår, funktionen get som används på matkassen kan ta ett andra argument. Om nyckeln man försöker använda inte finns i matkassen kommer funktionen returnera det andra argumentet. Funktionen setdefault har sina användningsområden, men kanske inte just här.

TL, DR; Python dictionaries är användbara saker och funktionerna get() och setdefault() är coola och kan vara kul att känna till.

Från bugg till segerdans

När jag väl hade bestämt mig för att lösa det här pusslet med hjälp av programmering tog jag och ägnade hela lördagen till att få mitt program att fungera. Det var mycket frustrerande när jag inte kunde få programmet att fungera på natten till söndagen och till slut fick jag gå och lägga mig med buggarna kvar. Men att sova på ett programmeringsproblem kan vara ett mycket enkelt sett att komma framåt och morgonen därpå gick jag igenom min kod och kunde göra den mycket enklare och till slut hade jag fått fram en lösning till Professor Spelet, mitt uppdrag var slutfört.

Låt mig därmed presentera koden till mitt program. Det finns säkert några buggar kvar och designen inte är den bästa. Kommentarer som tillför mer förvirring än förståelse finns det gott om, sånt tycker jag är kul.

Musikförslag till när ni läser koden:

KOD

2 reaktion på “Professorer och Python

  1. Alex

    Hur gick det då?!
    Fick du ut det?
    Vi hade ett liknande spel när jag var liten som hette rimini… det kanske också skulle fungera (förhoppningsfull)

    Är Jonas ett alias för Johan? ;)

    1. Eric Henziger Inläggsförfattare

      Japp, om man kör koden i inlägget så försöker den lägga pusslet någon minut och till slut lyckas den få fram en lösning :)

      Du får ta och gräva fram det där Rimini-spelet och klura ut en algoritm så kan vi skriva ett program som löser det också ;)

      Svårt det där med att hålla koll på namn på barn förresten, men nu heter Johan just Johan och inget annat, tack!

Kommentera