Je krijgt een reeks balkvormige dozen met dimensies (lengte, breedte, hoogte). Die dozen kunnen vrij geroteerd worden, zodat er eigenlijk 6 3-tallen met elke doos overeenkomen. We beschouwen enkel de oriëntaties waarbij $$lengte <= breedte $$ zodat je per fysieke doos hoogstens drie verschillende oriëntaties kan beschouwen.

Het probleem dat zich stelt is een zo hoog mogelijke toren te bouwen, waarbij het grondvlak van elke doos binnen het topvlak van de doos eronder past (m.a.w. lengte en breedte van het grondvlak van de bovenste doos zijn strikt kleiner dat resp. lengte en breedte van het topvlak van de doos eronder).

In deze oefening bouwen we een aantal klassen om dit stapelprobleem op te lossen via een aantal verschillende strategiëen.

Klasse Doos

Een fysieke door wordt gekenmerkt door 3 dimensies, namelijk lengte, breedte en hoogte. Programmeer in deze klasse:

Voorbeeld

doos1 = Doos(1, 4, 3)
doos2 = Doos(10, 8, 7)
print(doos1) #[1,4,3]
print(doos2) #[8,10,7]
doos1 < doos2 #False
doos2 < doos1 #True
print(doos1*0) #[1,4,3]
print(doos1*1) #[3,4,1]
print(doos1*2) #[1,3,4]

Klasse StapelProbleem

Een object van deze klasse stelt een probleemstelling voor, gekenmerkt door de dozen die kunnen gestapeld worden. Programmeer in deze klasse:

Voorbeeld

sp = StapelProbleem()
for (l, b, h) in zip([8, 15, 4],[17, 11, 16],[9, 11, 9]):
	sp += Doos(l, b, h)
print(sp) #(3,[[8,17,9],[11,15,11],[4,16,9]])
for (l, b, h) in zip([18, 18, 19],[10, 15, 12],[15, 12, 14]):
	sp += (l, b, h)
print(sp) #(6,[[8,17,9],[11,15,11],[4,16,9],[10,18,15],[15,18,12],[12,19,14]])
sp.geldige_stapel([2, 5], [2, 1]) #False
sp.hoogte([2, 5], [2, 1]) #-1
sp.geldige_stapel([4, 5, 1, 0], [0, 2, 2, 2]) #True
sp.hoogte([4, 5, 1, 0], [0, 2, 2, 2]) #63
sp.geldige_stapel([4, 1], [0, 0]) #True
sp.hoogte([4, 1], [0, 0]) #23

Elk van onderstaande klassen beschikt over de methode bouw_stapel() met als enig argument een object van de klasse StapelProbleem. Het resultaat van de methode is een oplossing van het stapelprobleem, verkregen door toepassing van een welbepaalde strategie (zie beschrijving van de klassen zelf). Het resultaat van de methode bouw_stapel() is een tuple, bestaande uit twee lijsten (dit zijn de lijsten zoals beschreven in de methode zoek_stapel() van de klasse StapelProbleem). De strategieën EenvoudigeStrategie en SorteerStrategie leveren een oplossing waarbij de dozen in hun originele stand gebruikt worden (de 2de lijst bestaat dus steeds enkel uit nullen). In de strategie RoteerSorteerStrategie worden ook andere standen van de dozen beschouwd.

De tekst hieronder beschrijft telkens de te volgen strategie bij het genereren van oplossingen voor het stapelprobleem.

Klasse EenvoudigeStrategie

Beschouw de dozen in de volgorde en stand waarin ze toegevoegd werden aan het probleem. Start bij de eerste doos, en probeer alle dozen te stapelen in de volgorde waarin ze toegevoegd werden. Sla dozen die niet passen over.

Klasse SorteerStrategie

Sorteer de dozen volgens dalende oppervlakte van hun grondvlak, in de stand waarin ze toegevoegd werden (voor gelijke oppervlakten wordt de originele ordening gerespecteerd). Pas dezelfde strategie als in de klasse EenvoudigeStrategie toe op de dozen, in deze aangepaste volgorde. Let erop dat rangnummers in het resultaat verwijzen naar de ORIGINELE volgorde van de dozen.

Klasse RoteerSorteerStrategie

Bouw een lijst van alle mogelijke standen van elke doos, en sorteer deze lijst (die dus 3x meer dozen bevat) volgens hetzelfde criterium als in de klasse SorteerStrategie vermeld. Bouw nu een stapel, gebruik makend van dezelfde aanpak (dus probeer de dozen in deze nieuwe volgorde te stapelen, en sla dozen over die niet passen). Hierbij moet je ervoor zorgen dat elke doos maar 1 keer gebruikt kan worden: zodra je een doos gebruikt hebt in de stapeling, kan je geroteerde versies van diezelfde doos (die eventueel verderop in de lijst voorkomen) niet meer gebruiken.

Voorbeeld

sp = StapelProbleem()
for (l, b, h) in zip([9, 14, 17, 20, 16, 4, 16],[20, 7, 6, 19, 7, 15, 4],[8, 16, 7, 18, 17, 11, 10]):
	sp += Doos(l, b, h)
print(sp) #(7,[[9,20,8],[7,14,16],[6,17,7],[19,20,18],[7,16,17],[4,15,11],[4,16,10]])
eenvoudig = EenvoudigeStrategie()
eenvoudig.bouw_stapel(sp) #([0, 1], [0, 0])
sorteer = SorteerStrategie()
sorteer.bouw_stapel(sp) #([3, 4, 5], [0, 0, 0])
roteer_sorteer = RoteerSorteerStrategie()
roteer_sorteer.bouw_stapel(sp) #([3, 4, 1, 5, 0, 2], [0, 1, 1, 1, 2, 2])
sp.zoek_stapel(eenvoudig) #([0, 1], [0, 0])
sp.zoek_stapel(sorteer) #([3, 4, 5], [0, 0, 0])
sp.zoek_stapel(roteer_sorteer) #([3, 4, 1, 5, 0, 2], [0, 1, 1, 1, 2, 2])