#Klooienmetcomputers

Life

Arnout van Kempen over rommelen in een digitale wereld.

De wiskundige Conway bedacht ooit The Game of Life. Het is niet echt een spel, maar wel leuk voor de liefhebber. De basisgedachte is heel simpel. Je hebt een oneindig veld, een soort dambord. En ieder vlak is een cel. Iedere cel leeft of is dood. Als je een nieuwe generatie van het veld wil bepalen, dan moet je van iedere cel het aantal buren tellen. Een levende cel blijft leven bij 2 of 3 buren. Een dode cel komt tot leven bij 3 buren. En een levende cel sterft bij 4 of meer buren of bij 2 of minder buren. Alle veranderingen in een generatie gebeuren gelijktijdig.

Zo op het oog simpele regels en niet direct iets waar je veel spektakel van verwacht. Toch blijkt dat op basis van deze simpele regels enorm complexe figuren gemaakt kunnen worden. Als je een groepje cellen als een object beschouwt, dan blijken er stabiele objecten te bestaan, pulsars, gliders die zich over het veld bewegen, glider kanonnen die constant gliders produceren en nog heel veel meer. Het blijkt zelfs mogelijk om het spel Life te bouwen met enkel objecten in Life. En om het nog gekker te maken, het is mogelijk om in Life een computer te bouwen die uitsluitend bestaat uit objecten in Life. Een dergelijke computer is 'Turing compleet' en kan dus alles wat een andere computer ook kan.

Daarnaast is het programmeren van Life een niet al te moeilijke uitdaging, maar wel een leuke. Er zitten grafische elementen in, je zal moeten nadenken over hoe een programma te structureren, enzovoort.

De uitwerking die ik van Life gemaakt heb en op GitHub heb geplaatst, werkt op ieder systeem dat met ncurses.h kan werken, in een terminal (dus tekst) omgeving. Op de Pi kan dat via SSH of MOSH, vanaf de CLI, of in een Terminal-window in de GUI. Daarbij maak ik gebruik van al het beschikbare scherm. Het veld met cellen sla ik daarom op in een dynamische array die dus met malloc() gemaakt zal moeten worden.
Wil je dat niet, dan zou je ook met een vaste array kunnen werken, bijvoorbeeld

bool veld[45][150][2]

De eerste twee indexen geven samen de x- en y-coördinaten weer. De derde index is nodig omdat je steeds de nieuwe generatie, cel voor cel, zal moeten opslaan zonder dat je de huidige generatie beïnvloedt. Dat ik voor een bool array kies komt omdat dat goed past bij de regels van het spel. Iedere cel is immers levend (true) of dood (false).

De oplossing met een dynamische array levert een aardiger resultaat, omdat je steeds het hele scherm kan gebruiken, maar het is wat meer werk. Je moet immers eerst een array veld[max-x] alloceren, dan voor iedere x een array[x][max-y], en tenslotte voor iedere x en y een array[x][y][soort] om de twee generaties uit elkaar te houden. Dat wordt dus een pointer naar een pointer naar een pointer naar een bool. En als alles klaar is moet je die ook weer stuk voor stuk vrijgeven.

Voor het overzicht is het handig om verschillende functies, zoals het tekenen van je veld op het scherm, het vullen van je veld, het berekenen van een nieuwe generatie, et cetera, apart te schrijven en dan in main() aan te roepen. Je kan daarbij met één globale array veld[x][y][soort] werken, die je dan vóór het begin van main() moet declareren. Dat is prettig simpel en onprettig slecht leesbaar. Maar erger, je maakt het jezelf dan heel lastig om nog met verschillende schermgroottes te werken. Daarom is het handiger je veld binnen main() te declareren, en via een pointer steeds door te geven aan de verschillende functies die je maakt. Hoe weten die functies nu hoe groot je dynamisch bepaalde array veld is? Daarvoor kan je je array in een struct plaatsen, samen met de maximale x en y. Dat geeft de hele zaak wat overzichtelijkheid mee.

Daarbij heb ik nog wat kleinigheden toegevoegd die ik zelf handig vond, bijvoorbeeld:

  • Het aantal generaties dat ./life uitvoert is 1000, tenzij je het programma hebt gestart met een numeriek argument, bijvoorbeeld ./life 500 voert 500 generaties uit. Linksboven in de hoek zie je de teller aflopen naar nul.
  • Je kan tekenen met toetsen die makkelijk in de hand liggen voor omhoog, omlaag (q en a), links en rechts (o en p). Met de spatiebalk zet je een cel aan of uit. En met t zet je tekenen aan, met g gummen, en met b is de functie weer blanco, en dus afhankelijk van de spatiebalk. Druk je op enter, dan ben je klaar.
  • Na iedere generatie wacht de computer tot je een toets indrukt. Hou je die ingedrukt dan gaat de computer vlot, maar niet extreem snel, door de generaties heen. Druk je op de f van fast, dan wacht de computer nergens meer op en wikkelt de generaties zo snel mogelijk af.
  • Omdat een oneindig veld nu eenmaal niet past op een eindig scherm, tel ik als rechter buurcellen van een cel die helemaal rechts staat de cellen helemaal links, en zo bij alle randen. Het gevolg is dat je als het ware op een soort bol zit; ga je aan een kant uit het scherm, dan kom je er aan de overkant weer in.

Kom je er niet uit, dan staat op GitHub mijn oplossing. Maar ik beloof dat het veel leuker is zelf tot een eigen oplossing te komen!

Wie mee wil doen met #klooienmetcomputers kan dat doen via GitHub. Maak een account op www.github.com en zoek naar Abmvk/kmc. Het account Abmvk volgen kan ook. Lezers zijn vrij te gebruiken wat ze willen en om zelf zaken toe te voegen of aan te passen, vragen te stellen of commentaar te leveren.

Arnout van Kempen di CCO CISA is Senior manager Risk & Compliance bij Baker Tilly. Hij schrijft op persoonlijke titel. Hij is lid van de Commissie Financiële verslaggeving & Accountancy van de AFM en lid van de signaleringsraad van de NBA. Daarnaast is hij diaken van het bisdom 's-Hertogenbosch.

Gerelateerd

reacties

Reageren op een artikel kan tot drie maanden na plaatsing. Reageren op dit artikel is daarom niet meer mogelijk.

Aanmelden nieuwsbrief

Ontvang elke werkdag (maandag t/m vrijdag) de laatste nieuwsberichten, opinies en artikelen in uw mailbox.

Bent u NBA-lid? Dan kunt u zich ook aanmelden via uw ledenprofiel op MijnNBA.nl.