Inleiding Op het web trof ik de "leap-frog puzzle" aan, een puzzeltje voor kinderen.Klik [hier] om het te spelen. De bedoeling is de kikkers zodanig te laten springen, dat ze van plaats verwisselen. Daarbij mag een kikker alleen naar voren springen naar een open plaats ernaast of over één andere kikker. Om nog wat origineels toe te voegen heb ik de kikkers door berggeiten vervangen en het spel "bokkesprongen" genoemd. Ook heb ik een paar niveaus ingevoerd. Klik [ hier] om "bokkesprongen" te spelen. In dit artikel leg ik uit hoe met een (Delphi) computerprogramma dit puzzeltje oplost. Tevens wordt een formule afgeleid voor het aantal benodigde sprongen als er 2 groepjes van k kikkers tegenover elkaar staan. Er is geen moeite gedaan om mooie springende kikkers of bokken te tekenen. In plaats daarvan noem ik de 3 linker kikkers X en de 3 rechter kikkers Y. Dit is dan de beginstand van de puzzle:
- een Y kikker springt alleen naar links - een kikker springt naar een open plaats direct ernaast of - over 1 kikker ernaast naar een open plaats Codering De plaats waar een letter staat noem ik een "veld".Een veld bevat : geen kikker, een X- of een Y kikker. type TkikkerSoort = (geen, kX, kY) var speelveld : array[1..6] of TkikkerSoort;Hoewel een sprong met het veldnummer kan worden aangegeven is het handiger om ook het veld waar de kikker heen springt te onthouden. type Tsprong = record org , dest : byte; //begin- en eindveld van een kikkersprong end; var sprongen : array[1..20] of TSprong; //alle gemaakte sprongen sprongNr : byte = 0; // de laatste sprongHieraan hebben we voldoende om aan de slag te gaan. Procedures en Functies In het programma kan, met KikkersUpDown control, het aantal kikkers per soort worden ingesteld van 1 tot en met 10.Het aantal kikkers wordt met k aangegeven. Het aantal velden is dan w = 2 * k + 1 procedure kikkersOpstellen zet de velden van array speelveld op de beginstand. Voor het tekenen van een veld wordt procedure TekenVeld aangeroepen. functie zoekoplossing levert resultaat "true" af als een oplossing is gevonden. Deze functie is karakteristiek voor het zoeken van oplossingen volgens de "brute kracht" methode. Daarbij worden systematisch alle mogelijkheden op het speelveld doorlopen. Hieronder de flowchart: Omdat er een paar programma-lussen door elkaar heen lopen is gestructureerd programmeren niet handig. Een paar labels en goto statements zijn hier, bij uitzondering, duidelijker. De functie sprongOK(nr : byte) : byte onderzoekt of de kikker in veld nr kan springen. Als dat zo is dan levert de functie het veld waarnaar dan gesprongen kan worden, anders is het resultaat 0. Hier kan men makkelijk verzanden in een woud van if...else statements, die erg onoverzichtelijk worden. Handiger is de situatie te coderen en de code aan een case statement aan te bieden. Het werkt als volgt: Zet code = $10 voor een X kikker en code = $20 voor een Y kikker. Zoek daarna alle velden af om de lege plaats te vinden. Verander de code afhankelijk van de positie van die lege plaats : 1 voor 1 rechts, 2 voor 2 rechts, 4 voor 1 links en 8 voor 2 links. Zodat nu bij de volgende codes deze resultaten horen
- $12....... 2 rechts - $14....... 1 links - $18....... 2 links De Knoppen We willen natuurlijk de gevonden oplossingen naspelen.Ook is het wel aardig om zelf naar oplossingen te zoeken. Daarom zijn er 3 speedbuttons geplaatst: playBtn Om zelf oplossingen te zoeken. Plaats de muispointer op de X of Y en klik om te zetten.analyseBtn Om de computer naar oplossingen te laten zoeken.replayBtn Om een oplossingen stap voor stap te tonen.Nog 2 bitbuttons zijn toegevoegd: goBtn Het opschrift wordt steeds aangepast aan de ingedrukte speedbutton.De knop zorgt voor terugspringen (bij playBtn.down), starten van zoekproces (analyseBtn.down) of het tonen van de volgende sprong (replayBtn.down). clearBtn Met deze knop wordt het speelveld in de beginstand gezet.Voor verdere details verwijs ik naar de source listing. Die kan je [ hier ] downloaden. Klik op het bliksem icoon bovenaan de pagina om alleen het programma te downloaden. Wiskunde Als er k kikkers van elke soort zijn dan heeft het spel w = 2k + 1 velden.Elke kikker moet tot de eindstand k + 1 velden verspringen, dus totaal moeten er 2k(k + 1) velden worden versprongen. Elke kikker moet bovendien minimaal over 3 andere kikkers heen springen, dat zijn k*k sprongen van 2 velden, waarbij dus 2k*k velden worden afgelegd. Er vinden dus maximaal 2k(k + 1) - 2*k*k = 2k enkelvelds sprongen plaats. Maximaal aantal sprongen is dus k*k + 2k = k(k + 2). Een spel met 3 kikkers per soort wordt dus maximaal in 3 * 5 = 15 zetten opgelost, waarbij we nog niet hebben bewezen dat die oplossing ook bestaat. Het programma toont echter aan dat er steeds 1 oplossing is in k(k + 2) zetten. |
|||||||