Norjee schreef op vrijdag 02 februari 2007 @ 01:25:
* Norjee mag nu vast wel zijn ideeën (helaas niet fatsoenlijk uitgewerkt) plaatsen
Wie heeft het probleem niet geïnterpreteerd als blokjes op volgorde droppen, maar zeg maar uit een solide blok "hapjes" halen, eventueel geinverteerd? Of wat ik deed een "vaatje" vullen, met als enige regel dat een blokjes met id 0 (het eerste blokje) niet boven een blokje met id 1 (tweede blokje) gedropt moest worden, dus stapelen en zo goed mogelijk passen zolang het nog mogelijk was het blokje met laagste id te plaatsten (en wilde dat niet uiteraard weer terug in je boom).
Ik had het nog veel simpeler. Mijn algoritme gaat gewoon de blokjes op alle mogelijke posities plaatsen en aan de hand van een score functie (dus niet de normale score, maar eentje die ook rekening houd met hoeveel gater er in zitten, hoe 'regelmatig' hij er uit ziet etc) beslissen waar hij het beste past.
Het voordeel is dat dit algoritme ook makkelijk uit te breiden is met een look-ahead, die een x aantal plekken vooruit alvast zet en dat pas de score gaat bekijken. Alleen als je dat direct met alles doet, dan krijg je veel te veel mogelijkheden. Stel gemiddeld kun je elk blokje op 30 verschillende manier plaatsen. Zonder in de boom te snijden zou je met een look-ahead van
x maar liefst 30
x mogelijkheden krijgen. Die is veel te veel (voor 3 is die al 27.000, voor 4 al 810.000 etc...).
Daarom gebruik ik dezelfde score functie om de boom te 'snoeien'. Op het huidige niveau (dus het eerst volgende blokje dat geplaatst moet worden) gaat mijn algoritme de beste 4 opties uitzoeken (die aantal is aan te passen) en deze in 4 threads gooien om de rest van de boom te berekenen. Hierna wordt op elk volgend niveau de beste 2 uitgezocht, totdat we op de gewenste diepte zijn. Hierdoor wordt per stap veel minder opties bekeken en kan ik op een redelijke machine tot 10 stappen vooruit kijken.
Naast dit algoritme heb ik natuurlijk nog wat andere Java optimalisaties gedaan, zoals een pool aanmaken voor de velden. Een nieuw veld creeren in het geheugen in namelijk vrij zwaar en daarom recycle ik de velden in een pool. Een bijkomend voordeel is dan dat de garbage collector het ook niet zo moeilijk heeft. Plus dat ik als ik de blokken laad ik gelijk alle mogelijke rotaties + schuivingen in het geheugen opsla als een apart blok. Daarbij wordt ook rekening gehouden dat sommige rotaties gelijk zijn aan andere (bijvoorbeeld een vierkantje van 4 blokjes kun je zoveel roteren als je wilt, maar hij blijft het zelfde). Hierbij hoeven natuurlijk een hoop mogelijkheden nooit bekeken te worden.
In de code kun je wel aardig zien hoe ik dat heb uitgewerkt
pff.. wat een lang verhaal