Lesbrief 5.1: bouwen van structuren met .csv-bestand. 

We kunnen nu blokken plaatsen en ook wat grote structuren bouwen door middel van for loops, maar die structuren kunnen niet veel anders zijn dan grote vlakken en pilaren. Om te zorgen dat we makkelijk veel blokken kunnen plaatsen kunnen we text bestandjes gebruiken om te vertellen welke blokken geplaatst moeten worden.

We gaan nu zo’n text bestandje maken.

Ga naar file, New File

En type de volgende regels in

1,1,1,1,1,1,1,1,1,1
0,0,0,0,0,0,0,0,0,1
1,1,1,1,1,0,1,1,0,1
1,0,0,0,0,0,1,0,0,1
1,0,1,1,0,1,1,1,1,1
1,0,1,0,0,0,0,0,0,1
1,0,1,1,1,1,1,0,1,1
1,0,0,0,0,0,1,1,1,1
1,0,1,1,1,0,0,0,0,1
1,1,1,1,1,1,1,1,0,1

Nu moeten we het bestand op een speciale manier opslaan, ga naar File à Save as, voer bij bestandsnaam doolhof.csv in en zorg dat achter Opslaan als: All files (“.”) komt te staan. Nu heb je het bestand opgeslagen als een csv bestand, dit is een speciaal bestand wat makkelijk gelezen kan worden door een python script.

We gaan nu het script schrijven dat ons doolhof.csv zal gebruiken om een doolhof in minecraft te bouwen.

Eerst de twee standaard regels:

import mcpi.minecraft as minecraft
mc = minecraft.Minecraft.create()

Nu moeten we zorgen dat ons script weet welk bestandje hij moet openen, dit doen we door de volgende regels te typen:

Doolhof = open(“doolhof.csv”, “r”)

We maken een variabel aan en in dat variabel zetten we de inhoud van het doolhof bestandje door het commando open te gebruiken. Het open commando werkt als volgt, tussen de haken komt eerst de naam van het bestand dat geopend moet worden en daarna komt er een komma met daarachter “r” of “w”, als je r invoert zal het bestand gelezen worden, en als je w kan je dingen in het bestand gaan schrijven.

Nu moeten we weten wat de coördinaten van de speler zijn om te zorgen dat het doolhof op de juiste plaats komt te staan:

pos = mc.player.getTilePos()
start_x = pos.x+1
start_y = pos.y
start_z = pos.z+1
z = start_z

normaal gebruiken we alleen pos=mc.player.getTilePos(), maar deze keer hebben we start_x, start_y en start_z toegevoegd om het script makkelijk te vertellen waar het eerste blokje van het doolhof moet komen te staan. Ook hebben het het variabel z toegevoegd, omdat de z waarde in het script gaat veranderen

We gaan nu de echte magie van for loops toepassen, we maken een for loop die voor iedere regel in ons doolhof.csv bestandje een keer rond gaat:

for line in Doolhof.readlines():

We moeten bij iedere regel zorgen dat de cijfertjes van die regel gesplitst worden in aparte cijfers:

data = line.split(“,”)

hierdoor leest het python script de regel door en splits hij die regel bij een komma, ieder stukje wordt in de data array gestopt, voor een regel die er bijvoorbeeld zo uit zag:

1,0,0,0,0,0,1,0,0,1

Wordt de data array:

data[0] =1
data[1] =0
data[2] =0
data[3] =0
data[4] =0
data[5] =0
data[6] =1
data[7] =0
data[8] =0
data[9] =1

Deze array gaan we in de volgende for loop helemaal doorlopen, maar eerst moeten we nog een x variabel zetten omdat de x ook de hele tijd gaat veranderen net zoals de z:

x = start_x

nu komt de for loop die voor iedere “cell” / waarde van de data array een keer rond zal gaan:

for cell in data:

en in deze for loop moet het blokje geplaatst worden met de juiste block id, want de rede dat we nullen en enen hebben gebuikt in het doolhof bestand is omdat 0 de block id is van lucht en 1 de block id is van steen:

mc.setBlock(x,  start_y,  z,  int(cell))
x = x + 1

we zetten nu een blok op de plaats x,  start_y (de y waarde van de speller) en z en met als block id de waarde van cell. We gebruiken ook int(cell) omdat  het script normaal zou denken dat de informatie die in het variabel een stukje tekst is, maar doordat we int() er omheen zetten zal het worden gelezen als een cijfer.  Hierna zorgen we dat x verhoogd wordt met 1 en hierdoor komt het volgende blok naast het vorige blok te staan.

We moeten nu deze for loop afsluiten en terug gaan naar de vorige for loop door enter en dan 1 keer backstage in te drukken. Hier zetten we

z = z + 1

dit zorgt ervoor dat de de volgende regel van het bestand naast de vorige komt de staan en er niet overheen geplaatst wordt.

Als het goed is ziet het script er nu zo uit:

Als je het script nu uitvoert zul je een doolhof krijgen van een laag hoog, het is dus niet heel moelijk. Daarnaast is er ook geen vloer. We kunnen dit gaan veranderen door in plaats van een 2d structuur te maken met maar een laag, een 3d structuur te maken met 3 lagen. Om dit te doen moeten we een nieuw csv bestandje aan maken dat de informatie bevat voor ons 3Ddoolhof, dus File à New File, dan File à Save As en dan als naam 3Ddoolhof.csv en bij opslaan als weer All files (“.”)

Ten eeste moeten we wat gegevens in voeren die ons programma gaan vertellen hoe lang(x), hoog(y) en breed(z) het doolhof of het gebouw wat in het bestand staat zal zijn, ons doolhof wordt 10 blokjes lang, 3 blokjes hoog en 10 blokjes breed, dus de eerste regel komt er zo uit te zien:

10,3,10

Hierna komt een blanke regel en dan gaan we beginnen aan de eerste laag van het doolhof, de grond, deze gaat uit gras bestaan en gras heeft een block id van 2, dus die laag komt er zo uit te zien:

2,2,2,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2
2,2,2,2,2,2,2,2,2,2

Hierna komt weer een blanke regel en dan komt de volgende laag, het doolhof zelf:

1,1,1,1,1,1,1,1,1,1
0,0,0,0,0,0,0,0,0,1
1,1,1,1,1,0,1,1,0,1
1,0,0,0,0,0,1,0,0,1
1,0,1,1,0,1,1,1,1,1
1,0,1,0,0,0,0,0,0,1
1,0,1,1,1,1,1,0,1,1
1,0,0,0,0,0,1,1,1,1
1,0,1,1,1,0,0,0,0,1
1,1,1,1,1,1,1,1,0,1

En daarna komt weer dezelfde laag om te zorgen dat de muren van het doolhof 2 hoog zijn, vergeet de blanke regel tussen deze twee lagen niet:

1,1,1,1,1,1,1,1,1,1
0,0,0,0,0,0,0,0,0,1
1,1,1,1,1,0,1,1,0,1
1,0,0,0,0,0,1,0,0,1
1,0,1,1,0,1,1,1,1,1
1,0,1,0,0,0,0,0,0,1
1,0,1,1,1,1,1,0,1,1
1,0,0,0,0,0,1,1,1,1
1,0,1,1,1,0,0,0,0,1
1,1,1,1,1,1,1,1,0,1

Het bestand zou er nu zo uit moeten zien:

csv bestand python

Nu gaan we het script schrijven dat dit bestand kan veranderen in een 3D structuur in minecraft, maak een nieuw bestand en noem het 3Ddoolhof.py (laat zien hoe dit moet tom)

Begin met de standaard 2 regels:

import mcpi.minecraft as minecraft
mc = minecraft.Minecraft.create()

Dan moeten we het bestandje openen:

Gebouw = open(“3Ddoolhof.csv”,”r”)

We gebruiken hier gebouw in plaats van doolhof omdat we dit script ook zouden kunnen gebruiken om andere dingen uit te printen naast het 3D doolhof. We moeten nu de eerste regel lezen om het script te vertellen hoe breed, hoog en lang de structuur is:

regels = Gebouw.readlines()
coordinaten = regels[0].split(“,”)
breedte_x = int(coordinaten[0])
hoogte_y = int(coordinaten[1])
lengte_z = int(coordinaten[2])

door dit script wordt iedere regel van het bestandje 3Ddoolhof in een deel van de array regels gezet, de eerste regel van het bestandje is dus regels[0], de tweede is regels[1], de derde is regels[2] enzovoorts. We moeten de eerste regel lezen om uit te vinden hoe breed hoog en lang het gebouw in het bestandje is,  de breedte hoogte en lengte staan met komma’s van elkaar gescheiden dus als we de eerste regel (regel[0]) splitten bij iedere komma zullen de eerste drie getallen opgeslagen worden in het variabel coordinaten. Het eerste getal (coordinaten[0]) is de breedte, het tweede getal (coordinaten[1]) is de hoogte en het laatste getal (coordinaten[2]) is de lengte. Let op dat je int gebruikt want anders zou het script de getallen niet kunnen gebruiken om mee te reken omdat hij het ziet als tekst.

We moeten ook nog zorgen dat ons gebouw dicht bij ons komt te staan en daarvoor hebben we de coordinaten van de persoon nodig, en dan moeten we zorgen dat de coordinaten van het eerste blok niet recht op ons hoofd staan:

pos = mc.player.getTilePos()
start_x = pos.x + 1
start_y = pos.y
start_z = pos.z+1

Om te zorgen dat ons programma kan uitvinden welke regel hij moet gaan lezen gaan we een variabel regelid bij houden:

regel_id = 1

nu gaan we de eerste for loop van ons script schrijven, deze loop moet een keer rond gaan voor iedere verdieping, voor iedere y waarde:

for y in range(hoogte_y):
regel_id = regel_id + 1

In dit deel van de loop wordt er een bij de regel_id opgeteld, dit is omdat er voor iedere laag in het bestandje een blanke regel stond, door regel_id 1 omhoog te zetten slaan we die lijn over, in de eerste ronde van de for loop zal regel_id 2 zijn en dat betekent regel 3 in ons bestandje, zoals je ziet klopt het dus.

Nu moeten we zorgen dat we iedere regel van een zo’n verdieping apart nemen en opslitsen bij iedere komma:

for x in range(breedte_x):
regel = regels[regel_id]
data = regel.split(“,”)
regel_id = regel_id + 1

Het aantal regels van iedere verdieping wordt bepaald door de breedte en daarom gebruiken we de for loop met als range breedte_x. Nu komt de regel_id van pas, omdat dit variabel weet bij welke regel we zijn, we zetten de regel waar nu zijn in het variabel regel en splitsen die regel dan bij iedere komma weer op en ieder deeltje van de regel komt dan in de data array te staan. Vervolgens verhogen we regel_id met 1 zodat we de volgende regel lezen in de volgende ronde van het script.

Nu moeten we voor ieder cijfertje in de regel een blok plaatsen:

for z in range(lengte_z):
mc.setBlock(start_x+x,start_y+y,start_z+z, int(data[z]))

Hier gebruiken de for loop met de range lengte_z, omdat lengte_z aan gaf hoeveel cijfertjes er per regel stonden. Om te zorgen dat ieder blok op de juiste plaats komt de staan is bij ieder deel van het coordinaat van het blok een x, y of z waarde opgeteld. Voor de eerste laag is y 0, want dan zitten we in de eerste ronde van de y loop. Voor de eerste regel is x 0, want dan zitten we in de eerste ronde van de x loop en voor het eerste blok van de regel is z 0, want dan zitten we in de eerste ronde van de z loop. Bij de tweede ronde van de z loop staat z op een en zal er dus 1 bij start_z worden opgeteld waardoor het volgende blokje naast het vorige blokje komt de staan, als de hele z loop is voltooid dan wordt x een hoger en zal de volgende rij naast de vorige rij komen te staan. Als dan de hele x loop is voltooid en iedere regel van de eerste laag is gelegd, zal de volgende ronde voor de y loop beginnen en zal y een omhoog gaan, hierdoor komen de nieuwe blokjes een blokje hoger te liggen dan de oude en zullen ze erbovenop komen te liggen. Om het script te vertellen welk id het blokje heeft dat we aan het creëeren zijn gebruiken we data[z], want z geeft ook aan bij welk blokje we in de regel zijn, en als we die waarde in de data array opzoeken krijgen we het block id dat we in het bestand hadden ingevoerd. We moeten natuurlijk wel int() eromheen zetten anders weet het script weer niet dat we een getal willen en geen tekst.

Het script ziet er als het goed is zo uit:

python bouw structuren

Je kunt nu ook een eigen bestandje maken met bijvoorbeeld het model voor een boom. Let op dat je de eerste getalletjes van het bestandje dan goed invult en dat je het bestandje als een .csv bestand op slaat. Als je dat gedaan hebt moet je de naam nog invullen in het begin van het script, waar op dit moment nog 3Ddoolhof.csv staat.

Inscannen van structuren

Zojuist hebben we een script geschreven dat een tekst bestandje kan uitlezen om een gebouw in minecraft te printen. Het is echter veel werk om al de bestandjes zelf te typen en precies uit te zoeken welke blok op welke plaats moet komen te staan, om dit makkelijk te maken kunnen we een script maken dat gebouwen die in de minecraft wereld staan scant en in een tekst bestandje zet, wat dan vervolgens gebruikt kan worden door ons vorige script om in de wereld gezet te worden.

Maak een nieuwe file genaamd 3Dscan (Tom leg uit hoe dit moet) en begin met de twee standaard regels:

import mcpi.minecraft as minecraft
mc = minecraft.Minecraft.create()

We moeten ook weten op welke plek we staan om de structuur naast ons te scannen:

pos = mc.player.getTilePos()
start_x = pos.x+1
start_y = pos.y
start_z = pos.z+1

Nu moeten we het script vertellen welk bestand hij moet gaan schrijven, bijvoorbeeld boom.csv

Gebouw = open(“boom.csv”,”w”)

Zoals je ziet is hier “w” gebruikt in plaats van “r”, omdat we nu een bestandje gaan schrijven en niet lezen.

De eerste regel van het bestandje bevatte de breedte, hoogte en lengte, dus die moeten we nu invoegen:

breedte_x = 5
hoogte_y = 5
lengte_z = 5
Gebouw.write(str(breedte_x)+”,”+str(hoogte_y)+”,”+str(lengte_z)+” \n”)

We hadden Gebouw gebruikt bij de vorige regel voor het open commando, daarom moeten we dit variabel gebruiken bij alle acties die te maken hebben met schrijven van het bestandje. Om iets in het bestandje te schrijven gebruiken we .write(), met tussen de haken de tekst, str(breedte_x)+”,”+str(hoogte_y)+”,”+str(lengte_z)+” \n” ten eerste komt er 5 te staan, want dat is de tekst die in breedte_x staat, dan zetten we daar een komma achter met “,” en dan komt de hoogte, die opgeslagen is in het variabel hoogte_y waarvan we de tekst weer pakken door str() er omheen te zetten, we zetten weer een komma neer en dan komt de lengte, die opgeslagen zit in het variabel lengte_z. Als je later iets wil scannen dat een andere grote heeft, kun je deze waardes aanpassen. Na str(lengte_z) komt “\n”, dit betekent dat er een enter ingedrukt zal worden, het textbestand zou er nu zo uit zien:

5,5,5
Nu moeten we dezelfde procedure volgen als bij het vorige script van het doolhof, we moeten beginnen met de for loop voor iedere laag (voor de hoogte):

for y in range(hoogte_y):
Gebouw.write(“\n”)

De range van de y loop is weer hoogte_y net zoals bij het 3Ddoolhof script maar in plaats van dat we een regel overslaan zoals in het 3Ddoolhof script, moeten we nu die blanke regel schrijven aan het begin van iedere verdieping, dat doen we met .write(“\n”).

Nu moeten we iedere regel weer apart nemen, net zoals in het 3Ddoolhof script:

For x in range(breedte_x):
regel = “”

We hebben als range breedte_x gebruikt omdat de breedte van de structuur bepaald hoeveel regels er per verdieping staan. Ook beginnen we met het schrijven van de regel, er staan alleen nog maar twee aanhalingstekens omdat we er nog niets neer kunnen zetten maar wel moeten vertellen dat we begonnen zijn aan de regel zodat we verder in script dingen eraan toe kunnen voegen.

Nu moeten  ieder blok toe gaan voegen in de regel die we in de x for loop hebben geselecteerd:

for z in range(lengte_z):
blockid = mc.getBlock(start_x+x, start_y+y, start_z+z)
if regel != “”:
regel = regel + “,”
regel = regel + str(blockid)
Gebouw.write(regel + “\n”)

Dus, we gebruiken lengte_z als range, omdat dit variabel bepaalt hoeveel blokjes er per regel staan. Dan gaan we opzoeken welk blokje we moeten scannen, de coordinaten werken precies hetzelfde als de coordinaten van het printen van een blokje in het 3Ddoolhof script, maar nu gebruiken we mc.getBlock(), dit is een commando dat ons script verteld welk blokje op de plaats staat die wordt aangegeven. De id van dit blokje slaan we vervolgens op in blockid. Dan kijken we of er al iets in de regel staat, dus als de regel niet gelijk is aan (!=) “”. Als dit het geval is moeten we eerst een komma plaatsen om het nieuwe blockid te scheiden van het block id dat hiervoor is ingevoerd. Daarna voegen we het blockid toe aan de regel. Als hij alle blokjes van een lijn heeft opgeschreven en dus de hele z loop af heeft gemaakt moet hij de regel in het bestandje zetten en naar de volgende regel gaan, dat gebeurt in Gebouw.write, hij schrijft dan alles wat we in het variabel regel hebben gezet en zet er nog een \n achteraan om te zorgen dat we op de volgende regel komen.

We moeten nu het bestand sluiten zodat het later gebruikt kan worden door ons print script bijvoorbeeld

Gebouw.close()

Met dit commando sluiten we het bestand. Het is belangrijk dat dit commando helemaal aan het begin van de regel staat zonder witte ruimte ervoor want dan zou het nog in de loop zitten en dat moet niet zo zijn. Het script zal er zo uit moeten zien:

python scan structuren

In deze les heb je geleerd: 

  • Wat een .csv-bestand is.
  • Hoe je een .csv-bestand kunt lezen en schrijven met Python.
  • Hoe je met een .csv-bestand een gebouw kunt maken met Python in Minecraft.
  • Hoe je met een. .csv-bestand een gebouw kunt inscannen met Python in Minecraft.
Categorieën: Python