turn
und comp
.
turn
führt einen (Halb-)Zug durch, und stellt fest, ob
der Zug das Spiel beendet. Es wird wie folgt aufgerufen:
turn
move a1 a2 a3 a4 a5 a6 ascore b1 b2 b3 b4 b5 b6 bscore
move kann 1-6 sein, und gibt an, aus welcher Mulde (a1...a6) der Spieler die Steine nimmt. a1 a2 a3 a4 a5 a6 sind die Mulden des Spielers, der am Zug ist, b1 b2 b3 b4 b5 b6 die seines Gegners. ascore gibt an, wieviel der Spieler am Zug insgesamt gefangen hat, bscore, wieviel sein Gegner gefangen hat. turn gibt den alten und neuen Spielstand in folgender Form aus:
b6 b5 b4 b3 b2 b1 bscore ascore a1 a2 a3 a4 a5 a6Weiters gibt es den Spielstand in der Form aus, die für den nächsten Aufruf von
turn
sinnvoll ist (also mit vertauschten
Seiten). Beispiel: Der Aufruf
turn 4 1 15 10 9 7 0 0 1 2 1 1 1 0 0produziert folgende Ausgabe:
Old position: 0 1 1 1 2 1 0 0 1 15 10 9 7 0 New position: 1 2 2 2 3 2 0 0 2 15 10 0 8 1 input for opponent move: 2 3 2 2 2 1 0 2 15 10 0 8 1 0Jetzt kann man die letzte Zeile als Teil der Eingabe für den nächsten Zug verwenden. Wenn der andere Spieler zum Beispiel aus seiner 5. Mulde nehmen, will, kann er schreiben:
turn 5 2 3 2 2 2 1 0 2 15 10 0 8 1 0Wobei der Teil hinter
turn 5
die letzte Zeile der Ausgabe
des vorigen Zugs ist.
comp
schlägt einen Zug vor. Rufen
Sie sie wie folgt auf:
comp
depth a1 a2 a3 a4 a5 a6 ascore b1 b2 b3 b4 b5 b6 bscore
wobei depth die Suchtiefe angibt, und der Rest den
aktuellen Spielstand, wie bei turn
. Man kann sich zum
Beispiel mit
comp 10 2 3 2 2 2 1 0 2 15 10 0 8 1 0vom Computer einen Zug für die zweite Spielsituation oben empfehlen lassen.
comp
. make
bench
ruft das Programm mit einer bestimmten Eingabe auf. Die
Originalversion produziert auf der g0 folgendes Resultat:
LC_NUMERIC=en_US.utf8 perf stat -B -e cycles:u -e instructions:u -e branches:u -e branch-misses:u comp 12 0 14 9 8 7 5 0 0 1 0 0 0 4 0 Position: 4 0 0 0 1 0 0 0 0 14 9 8 7 5 Best move (1-6): 5 Value: -1 Performance counter stats for 'comp 12 0 14 9 8 7 5 0 0 1 0 0 0 4 0': 344,306,194,571 cycles:u 711,065,944,240 instructions:u # 2.07 insn per cycle 123,045,591,793 branches:u 4,643,565,058 branch-misses:u # 3.77% of all branches 102.935136358 seconds time elapsedVergleichen Sie ihre optimierte Version mit der Originalversion auf dieser Eingabe bezüglich cycles:u (also Laufzeit im User-mode).
Wenn Sie gut optimieren, kann Ihr Programm deutlich tiefere Suchbäume in vertretbarer Zeit absuchen. Sie können daher auch noch angeben welche Tiefe Ihr Programm für die obige Stellung erreicht, ohne eine Laufzeit von 10s zu überschreiten, und wie lange die Suche dabei braucht (wobei das mit dem Original nur vergleichbar ist, wenn Sie dabei immer das gleiche Ergebnis liefern wie das Original mit dieser Tiefe liefern würde). Das Original erreicht Tiefe 10 und braucht dafür 13.6Gcycles bzw. 4.94s.
Es ist natürlich leicht, eine Version zu machen, die genau für diese Eingabe schnell ist (und für alle anderen so langsam wie vorher), aber damit würden Sie das Lehrziel verfehlen. Es geht also darum, eine Version zu produzieren, die beim Oware-Spiel allgemein schnell ist, nicht nur für diese Stellung. Dabei können Sie sich auf die Einschränkungen des Spiels (z.B. nur 48 Steine im Spiel) durchaus verlassen und für Ihre Optimierung ausnutzen.
Beschränken Sie den Speicherplatzverbrauch des Programms auf 5GB (relevant, wenn Sie Transpositionstabellen verwenden), damit mehrere Gruppen gleichzeitig auf der g0 arbeiten können.
Das eigentliche Ziel ist ja ein starker Computerspieler, der möglichst wenig Rechenzeit braucht. Es gibt eine Reihe bekannter Techniken (z.B. Ruhesuche), die die Spielstärke erhöhen sollten, aber wo das Ergebnis dann nicht direkt mit einer bestimmten Minimax-Tiefe vergleichbar ist (es können andere Zugempfehlungen herauskommen). Man müsste dann irgendwie die Spielstärke vergleichen, was sehr aufwändig ist. Aber wenn Sie in diese Richtung arbeiten wollen, lassen Sie sich nicht davon abhalten. Überlegen Sie sich, wie Sie zeigen können, dass Ihr Programm in weniger Zeit genauso viel leistet, oder in der gleichen Zeit mehr; idealerweise sollten Sie diese Argumente quantitativ untermauern können.
Der Code findet sich in oware.zip bzw. Sie können ihn
auf der g0
von /nfs/unsafe/httpd/ftp/pub/anton/lvas/effizienz-aufgabe19
kopieren.
![]() | Name | Last modified | Size | Description |
---|---|---|---|---|
![]() | Parent Directory | - | ||
![]() | Makefile | 2019-12-14 17:11 | 1.1K | |
![]() | comp.c | 2019-12-14 14:45 | 1.8K | |
![]() | oware.c | 2019-12-13 19:58 | 3.3K | |
![]() | oware.h | 2019-12-12 15:48 | 329 | |
![]() | oware.zip | 2019-12-14 19:51 | 6.6K | |
![]() | turn.c | 2019-12-13 19:39 | 1.3K | |