Commit f0ac7a6f authored by Viktor Bogischef's avatar Viktor Bogischef

Added code for pv-split

parent eeafc345
<h1>Aufgabe 5: Parallelisierung Spielsuche</h2>
<h2>Am Beispiel des Brettspiels Abalone<br>
HPC-Praktikum SS07</h2>
<P>
<h3>1. Minimax</h3>
Zur Einarbeitung in die f&uuml;r die sp&auml;tere Parallelisierung
ben&ouml;tigten Codeteile soll zun&auml;chst eine sequentielle
Minimax-Suchestrategie entwickelt werden.
Implementieren sie die Minimax-Suchestrategie f&uuml;r Abalone in einer
Klasse MinimaxStrategy mit OneLevelStrategy als Vorlage und
SearchStrategy::_maxDepth als Tiefe, bis zu der Minimax suchen soll;
Aufrufbeispiele und Details zum Code sind in der README-Datei zum Code
zu finden.
<P>
Welche Leistung (Einheit "Bewertete Stellungen pro Sekunde") erreichen Sie
bei Nutzung "bester" Compileroptionen auf der Altix
bei verschiedenen Maximal-Suchtiefen (2,3,4,5) bezogen auf
<UL>
<LI>die Anfangsposition des Spiels
<LI>die Position in "position-midgame1"
<LI>"position-midgame2" und
<LI>"position-endgame"?
</UL>
Notieren sie sich auch die absolute Anzahl durchgef&uuml;hrter Bewertungen.
Hinweis: "Bewertungen/s" gibt "player -v ..." aus.
<h3>2. Parallelisierung Minimax</h3>
Parallelisieren Sie die Minimaxsuche entweder mit OpenMP
(eventuell mit Workqueuing-Konstrukten; siehe Manual des Intel
Compilers) oder MPI
mit einer geeigneten Parallelisierungsstrategie
(f&uuml;r MPI m&uuml;ssen Sie player.c:main() entsprechend ab&auml;ndern).
<P>
Welchen Speedup
bekommen Sie f&uuml;r die in (1) beschriebenen Parameter, also bezogen
auf der Performance-Wert "Bewertungen/s" f&uuml;r 2,4,6,8 Prozessoren?
Wann kann der erreichbare Speedup von der aktuellen Stellung abh&auml;ngen?
<P>
Hinweis:<UL>
<LI>&Uuml;berlegen Sie, welche Variablen bei der Parallelisierung mit
OpenMP als privat deklariert werden m&uuml;ssen. Dazu geh&ouml;ren
bei C++ auch Objekte, die in jedem Thread privat vorhanden sein
m&uuml;ssen, damit sich die Threads keine Daten &uuml;berschreiben
(z.B. das Objekt f&uuml;r die Spielposition).
</UL>
<h3>3. Einfache Parallelisierung Alpha-Beta </h3>
Der vorgegebene Alpha-Beta-Alogrithmus (ABID) l&auml;sst unn&ouml;tige
Bewertungen aus. Um wieviel Prozent sinkt die absolute Anzahl
bewerteter Stellungen in den in Teilaufgabe (1) notierten F&auml;llen?
<P>
Was w&auml;re eine einfache Parallelisierung des Alpha-Beta-Algorithmus?
Implementieren Sie Ihre einfache Strategie. Der Suchparallelisierungs-Overhead
ist der Prozentsatz an unn&ouml;tig durchgef&uuml;hrten Bewertungen. Wie hoch
ist dieser Overhead in ihrer einfachen Strategie bei 2,3,4,6 Prozessoren und
den in Teilaufgabe (1) vorgegebenen Stellungen?
Welche Probleme hat die Parallelisierung ausserdem? Hinweise kann eine
Speedup-Kurve geben (und bei MPI-Code der Traceanalyzer!).
<h3>4. Effiziente Parallelisierung Alpha-Beta</h3>
Um zu einer besseren Parallelisierung zu gelangen, ist eine gut ausbalancierte
Partitionierung des erwarteten Berechnungsaufwandes wichtig. Man kann davon
ausgehen, dass der Alpha-Beta Suchbaum mit passender Heuristik der minimalen
Form sehr nahe kommt. Wie sieht diese aus?
<I>F&uuml;ndig wird man in "Lu: Parallel
Search of Narrow Game Trees", siehe HPC-Webseite</I>. In der Arbeit sind
auch Parallelisierungsstrategien beschrieben.
Eine wichtige Strategie ist
PVSplit, die in einem minimalen Alpha-Beta-Suchbaum die Kinder der sogenannten
ALL-Knoten in einer Tiefensuche parallel behandelt.
Implementieren Sie PVSplit in OpenMP oder MPI f&uuml;r Abalone.
Geben Sie entsprechend zu Aufgabe 3 Speedupwerte f&uuml;r ihre
Parallelisierung von PVSplit an.
<P>
Hinweise:<UL>
<LI>Bei Nutzung von OpenMP sollten Sie hier Workqueuing-Konstrukte
einsetzen
<LI>Welche Bedingung und Codestelle bezeichnet einen ALL-Knoten in PVSplit?
Genau an diesen Stellen muss parallelisiert werden.
</UL>
### Compiler
### Chosen compiler has to be in path (use "module" to setup environment)
# Use this for GCC (warning: GCC < 4.2.x does not support OpenMP)
#CXX = g++
# Use this for the Intel C++ compiler ("icc" is only the C version)
#CXX = g++
# Use this for MPI
CXX = mpiCC
### Options
# Useful options for GCC
#CXXFLAGS=-O3
#LDFLAGS=
# Useful options for Intel C++
CXXFLAGS=-O3
LDFLAGS=
LIB_OBJS = move.o board.o network.o search.o eval.o
SEARCH_OBJS = $(LIB_OBJS) search-abid.o search-onelevel.o search-minimax.o
#SEARCH_OBJS = $(LIB_OBJS) search-parallel-minimax.o search-parallel-abid.cpp
all: player
#start referee
player: player.o $(SEARCH_OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $< $(SEARCH_OBJS)
#start: start.o $(LIB_OBJS)
# $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $< $(LIB_OBJS)
#referee: referee.o $(LIB_OBJS)
# $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $< $(LIB_OBJS)
clean:
rm -rf *.o *~ player start referee networktest
networktest: tests/networktest.o network.o
$(CXX) -o networktest tests/networktest.o network.o
board.o: board.h board.cpp search.cpp
move.o: move.h move.cpp
network.o: network.h network.cpp
player.o: player.cpp
search.o: search.cpp board.cpp move.cpp
eval.o: eval.cpp board.cpp
start.o: start.cpp board.cpp move.cpp
referee.o: referee.cpp board.cpp move.cpp
search-onelevel.o: search.h board.h eval.h
search-abid.o: search.h board.h
search-minimax.o: search.h board.h eval.h
#search-parallel-minimax.o: search.h board.h eval.h
Sequentieller Computerspieler fuer Abalone
==========================================
Abalone ist ein Brettspiel der Kategorie "2-Personen-Nullsummen-Spiel
mit vollstaendiger Information." Dabei bedeutet "Nullsummen-Spiel",
dass der Vorteil des einen Spielers der Nachteil des anderen ist, und
"Vollstaendige Information", dass es keine Zufallskomponente gibt.
Die Regeln gibt es unter
http://uk.abalonegames.com/rules/basic_rules/official_rules.html
und eine GUI-Version fuer Linux gibt es bei den KDE3 Spielen
("Kenolaba"). Der "Netwerk-Modus" dieser GUI benutzt denselben
Kommunikationsbus (siehe unten) wie die Programme hier.
Technische Beschreibung
========================
Die Kommunikation zwischen den Spielern basiert auf dem Austausch von
Spielpositionen auf einem Kommunikationsbus, an den sich mehrere
Prozesse anschliessen koennen. Auf dem Bus versandte Spielpositionen
werden an alle angeschlossenen Prozesse weitergeleitet.
Ein Kommunikationsbus wird identifiziert ueber eine Nummer und einen
Rechnernamen, auf dem der Kommunikationsbus existiert (die Implementierung
benutzt fuer den Kommunikationsbus einen TCP-Port auf dem Rechner, der
frei sein muss; Standard-Busnummer ist 23412).
Bei den folgenden Programmen laesst sich der Kommunikationsbus mit
Parameter "-p" angeben. Debuginformationen werden mit "-v" oder "-vv"
(mehr) ausgegeben. Hilfe zu Kommandozeilenoptionen mit "-h".
Teil der Spielposition ist uebrigens die Zugnummer und eine globale Zeit
bis zum erzwungenen Ende der Partie in Sekunden (wichtig fuer den
Turniermodus bei Benutzung eines Schiedsrichters - siehe unten).
Programm "player"
-----------------
Dies ist ein Computerspieler, der eine vorgegebene Farbe spielt, die man
optional als Argument übergibt. Farben sind entweder "X" oder "O" (Standard).
Farbe X spielt z.B. das Kommando "player X". Eine Spielstärke als Zahl kann
in der Kommandozeile als zweites Argument angegeben werden. Wie dieser
Wert genutzt wird, hängt von der im Computerspieler genutzten Strategie
ab; bei Spiel auf Zeit beispielsweise ist eine Spielstärke ohne Bedeutung.
Der Computerspieler schliesst sich einem Kommunikationsbus an
(Standardbus: "localhost:23412"), und wartet auf Spielpositionen.
Bekommt er eine Position, in der er spielen soll, berechnet er den besten
Zug und schickt die resultierende Spielposition an den Bus zurueck.
Programm "start"
----------------
Dieses Programm startet Spiele, beobachtet sie, und beendet sich, wenn
ein Spieler gewonnen hat. Allerdings kann es keinen Einfluss darauf nehmen,
wenn ein Spieler betruegt, d.h. Spielpositionen verschickt, die er gar
nicht erreichen kann, oder bei einem Spiel auf Zeit die verfügbaren
Zeiten falsch abändert. Gibt man einen Dateinamen als Argument an,
startet das Spiel an der in der Datei vorgegebenen Position.
Programm "referee" ("Schiedsrichter")
-------------------------------------
Dies hat dieselbe Funktion wie "start", kann aber als Schiedsrichter ein Spiel
überwachen, indem er das Spiel zwischen 2 Kommunikationsbussen vermittelt.
Dazu muss auf dem einen Bus ein Spieler fuer "O", und auf dem anderen ein
Spieler fuer "X" sitzen.
Der Schiedsrichter verschickt die Startposition (bzw. Position aus einer
gegebenen Datei) an beide Busse und wartet auf neue Positionen, die er
nur dann weitergibt an den anderen Bus, wenn sie sich durch einen
gültigen Zug ergeben. Dabei gibt der Schiedsrichter allein die Zeit vor
(seit Start des Spiels oder wie in der Datei vorgegeben). Der Schiedsrichter
entscheidet auch, wann ein Spieler wegen Zeitueberschreitung vorloren hat.
Aufrufbeispiele
================
Kompilieren mit "make".
Ohne Schiedsrichter:
player O &
player X &
start
Mit Schiedsrichter:
player -p 3000 O &
player -p 4000 X &
referee -p 3000 -p 4000
Die Startreihenfolge ist jeweils egal, da "start" and "referee" die
aktuelle Position an neue Teilnehmer im Kommunikationsbus
verschicken. Damit kann man Teilnehmer jederzeit abschiessen ('kill'en) und
neustarten: Sie klinken sich automatisch wieder ein.
Bei einem Spiel auf Zeit startet der Schiedsrichter,
sobald ein einziger (!) weiterer Teilnehmer existiert.
Beispiel fuer Netwerkspiel mit Tunneln
======================================
Auf Rechner "comp1" soll Spieler O laufen, wird sind auf "mycomp".
Zwischen mycomp und comp1 ist eine Firewall, die nur SSH erlaubt.
Auf mycomp soll Spieler X und ein Beobachter/Starter laufen.
Zum Verständnis ist es wichtig zu wissen, dass ein "Kommunikationsbus"
aus Punkt-zu-Punkt TCP-Verbindungen zwischen allen Teilnehmern eines
Busses bestehen, wobei jeweils der nächstfreie TCP-Port benutzt wird.
Beim Start eines Teilnehmers belegt er einen eingehenden Port (LISTEN),
der der Kanalnummer oder einer nächsthöhrem unbelegten Port entspricht.
Da ein Spieler auf dem entfernten "comp1" laufen soll, starten wir
SSH mit einem lokalen Forward auf den entfernten Rechner. Für lokale
Teilnehmer scheint damit der entfernte Teilnehmer lokal zu existieren.
Da die 2 lokalen Teilnehmer vom entfernten Rechner aus erreichbar
sein müssen, müssen 2 weitere Tunnel vom entfernten Rechner auf den
lokalen Rechner eingerichtet werden ("remote forwards").
Einloggen auf comp1 (z.B. Kommunikationskanal 5000):
ssh -L 5000:localhost:5000 -R 5001:localhost:5001 -R 5002:localhost:5002 comp1
comp1> ./player -p 5000 O
mycomp>./player -p 5000 X &
mycomp>./start -p 5000
Implementierung einer eigenen Suchstrategie
===========================================
Der Code ist in relativ einfachem C++ geschrieben. Für ein zur
Implementierung einer eigenen Suchstratie ausreichendes Verständnisses
des Codes sollte es genügen, sich die in "search-onelevel.cpp" implementierte
Strategie genau anzuschauen. Dieser Code ist dazu ausführlich
dokumentiert, und zeigt, welche Schritte für eine eigene Suchstrategie
vorgenommen werden müssen.
Für eine neue sequentielle Strategie (oder Parallelisierung mit OpenMP)
reicht es aus, diese Datei als Vorlage zu nehmen. Bei Parallelisierung
mit MPI muss main() so abgeändert werden, dass "Rank 0" den bisherigen
Code darin ausführt, und jeder andere MPI-Task in eine zu implementierende
Funktion springt, die auf Anfragen von Rank 0 wartet (Master-Slave).
"search-onelevel.cpp" ist ein Beispiel einer einfachen Suchstrategie
mit einer Vorausschau von einem Zug. Im Gegensatz zu dieser einfachen
Strategie sollte immer eine einstellbare Suchstärke
berücksichtigt werden, die als "_maxDepth" in SearchStrategy
erreichbar ist, und über den Kommandozeilenparameter definiert wird.
Beispiel einer komplexen Suchstrategie (Alpha-Beta mit
Tiefensuche: "Alpha/Beta with Iterative Deepening") ist in
search-abid.cpp zu finden.
Die Auswahl einer Suchstrategie erfolgt mit "player -s <Nummer> ...",
wobei die Zuordnung zwischen der Nummer einer Strategie und ihrem
Namen in der Hilfe angegeben wird, erreichbar über "player -h".
Referee:
* Protocol extensions:
- ...
General:
* Network: Multiple messages on one TCP connection
* Network: Real asynch. breaks (really needed?)
* Gameconsole: Send messages
/*
* Classes
* - Board: represents a game state
* - EvalScheme: evaluation scheme
*
* (c) 1997-2005, Josef Weidendorfer
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "search.h"
#include "board.h"
extern int thread_rank;
#if 0
#include <assert.h>
#define CHECK(b) assert(b)
#else
#define CHECK(b)
#endif
/// MoveCounter
MoveCounter::MoveCounter()
{
init();
}
void MoveCounter::init()
{
for(int i=0;i < Move::typeCount;i++)
_moveCount[i] = 0;
for(int i=0;i < inARowCount;i++)
_rowCount[i] = 0;
}
int MoveCounter::moveSum()
{
int sum = _moveCount[0];
for(int i=1;i < Move::typeCount;i++)
sum += _moveCount[i];
return sum;
}
/****************************** Class Board ****************************/
/* Board for start of a game */
int Board::startBoard[]={
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 1, 1, 1, 1, 1, 10, 10, 10, 10, 10,
10, 1, 1, 1, 1, 1, 1, 10, 10, 10, 10,
10, 0, 0, 1, 1, 1, 0, 0, 10, 10, 10,
10, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10,
10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 10,
10, 10, 10, 0, 0, 2, 2, 2, 0, 0, 10,
10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 10,
10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 };
/* first centrum of board, then rings around (numbers are indexes) */
int Board::order[]={
60,
61,72,71,59,48,49,
62,73,84,83,82,70,58,47,36,37,38,50,
63,74,85,96,95,94,93,81,69,57,46,35,24,25,26,27,39,51,
64,75,86,97,108,107,106,105,104,92,80,68,56,45,34,23,12,
13,14,15,16,28,40,52 };
int Board::direction[]= { -11,1,12,11,-1,-12,-11,1 };
Board::Board()
{
clear();
_verbose = 0;
_ev = 0;
}
void Board::begin(int startColor)
{
int i;
for(i=0;i<AllFields;i++)
field[i] = startBoard[i];
storedFirst = storedLast = 0;
color = startColor;
color1Count = color2Count = 14;
_msecsToPlay[color1] = _msecsToPlay[color2] = 0;
::srand(0); // Initialize random sequence
}
void Board::clear()
{
int i;
for(i=0;i<AllFields;i++)
field[i] = (startBoard[i] == out) ? out: free;
storedFirst = storedLast = 0;
color1Count = color2Count = 0;
_msecsToPlay[color1] = _msecsToPlay[color2] = 0;
}
/** countFrom
*
* Used for board evaluation to count allowed move types and
* connectiveness. VERY similar to move generation.
*/
void Board::countFrom(int startField, int color,
MoveCounter& MCounter)
{
int d, dir, c, actField, c2;
bool left, right;
/* 6 directions */
for(d=1;d<7;d++) {
dir = fieldDiffOfDir(d);
/* 2nd field */
c = field[actField = startField+dir];
if (c == free) {
MCounter.incType( Move::move1 );
continue;
}
if (c != color)
continue;
/* 2nd == color */
MCounter.incRow( MoveCounter::inARow2 );
/* left side move 2 */
left = (field[startField + fieldDiffOfDir(d-1)] == free);
if (left) {
left = (field[actField + fieldDiffOfDir(d-1)] == free);
if (left)
MCounter.incType( Move::left2 );
}
/* right side move 2 */
right = (field[startField + fieldDiffOfDir(d+1)] == free);
if (right) {
right = (field[actField + fieldDiffOfDir(d+1)] == free);
if (right)
MCounter.incType( Move::right2 );
}
/* 3rd field */
c = field[actField += dir];
if (c == free) {
/* (c c .) */
MCounter.incType( Move::move2 );
continue;
}
else if (c == out) {
continue;
}
else if (c != color) {
/* 4th field */
c = field[actField += dir];
if (c == free) {
/* (c c o .) */
MCounter.incType( Move::push1with2 );
}
else if (c == out) {
/* (c c o |) */
MCounter.incType( Move::out1with2 );
}
continue;
}
/* 3nd == color */
MCounter.incRow( MoveCounter::inARow3 );
/* left side move 3 */
if (left) {
left = (field[actField + fieldDiffOfDir(d-1)] == free);
if (left)
MCounter.incType( Move::left3 );
}
/* right side move 3 */
if (right) {
right = (field[actField + fieldDiffOfDir(d+1)] == free);
if (right)
MCounter.incType( Move::right3 );
}
/* 4th field */
c = field[actField += dir];
if (c == free) {
/* (c c c .) */
MCounter.incType( Move::move3 );
continue;
}
else if (c == out) {
continue;
}
else if (c != color) {
/* 4nd == opponent */
/* 5. field */
c2 = field[actField += dir];
if (c2 == free) {
/* (c c c o .) */
MCounter.incType( Move::push1with3 );
continue;
}
else if (c2 == out) {
/* (c c c o |) */
MCounter.incType( Move::out1with3 );
continue;
}
if (c2 != c)
continue;
/* 5nd == opponent */
/* 6. field */
c2 = field[actField += dir];
if (c2 == free) {
/* (c c c o o .) */
MCounter.incType( Move::push2 );
}
else if (c2 == out) {
/* (c c c o o |) */
MCounter.incType( Move::out2 );
}
continue;
}
/* 4nd == color */
MCounter.incRow( MoveCounter::inARow4 );
/* 5th field */
c = field[actField += dir];
if (c != color)
continue;
/* 4nd == color */
MCounter.incRow( MoveCounter::inARow5 );
}
}
/* generate moves starting at field <startField> */
void Board::generateFieldMoves(int startField, MoveList& list)
{
int d, dir, c, actField;
bool left, right;
int opponent = (color == color1) ? color2 : color1;
assert( field[startField] == color );
/* 6 directions */
for(d=1;d<7;d++) {
dir = direction[d];
/* 2nd field */
c = field[actField = startField+dir];
if (c == free) {
/* (c .) */
list.insert(startField, d, Move::move1);
continue;
}
if (c != color)
continue;
/* 2nd == color */
left = (field[startField+direction[d-1]] == free);
if (left) {
left = (field[actField+direction[d-1]] == free);
if (left)
/* 2 left */
list.insert(startField, d, Move::left2);
}
right = (field[startField+direction[d+1]] == free);
if (right) {
right = (field[actField+direction[d+1]] == free);
if (right)
/* 2 right */
list.insert(startField, d, Move::right2);
}
/* 3rd field */
c = field[actField += dir];
if (c == free) {
/* (c c .) */
list.insert(startField, d, Move::move2);
continue;
}
else if (c == opponent) {
/* 4th field */
c = field[actField += dir];
if (c == free) {
/* (c c o .) */
list.insert(startField, d, Move::push1with2);
}
else if (c == out) {
/* (c c o |) */
list.insert(startField, d, Move::out1with2);
}
continue;
}
if (c != color)
continue;
/* 3nd == color */
if (left) {
if (field[actField+direction[d-1]] == free)
/* 3 left */
list.insert(startField, d, Move::left3);
}
if (right) {
if (field[actField+direction[d+1]] == free)
/* 3 right */
list.insert(startField, d, Move::right3);
}
/* 4th field */
c = field[actField += dir];
if (c == free) {
/* (c c c .) */
list.insert(startField, d, Move::move3);
continue;
}
if (c != opponent)
continue;
/* 4nd == opponent */
/* 5. field */
c = field[actField += dir];
if (c == free) {
/* (c c c o .) */
list.insert(startField, d, Move::push1with3);
continue;
}
else if (c == out) {
/* (c c c o |) */
list.insert(startField, d, Move::out1with3);
continue;
}
if (c != opponent)
continue;
/* 5nd == opponent */
/* 6. field */
c = field[actField += dir];
if (c == free) {
/* (c c c o o .) */
list.insert(startField, d, Move::push2);
}
else if (c == out) {
/* (c c c o o |) */
list.insert(startField, d, Move::out2);
}
}
}
void Board::generateMoves(MoveList& list)
{
int actField, f;
for(f=0;f<RealFields;f++) {
actField = order[f];
if ( field[actField] == color)
generateFieldMoves(actField, list);
}
}
Move Board::moveToReach(Board* b, bool fuzzy)
{
Move m;
/* can not move from invalid position */
int state = validState();
if ((state != valid1) && (state != valid2))
return m;
if (!fuzzy) {
if (b->moveNo() != _moveNo+1) {
if (_verbose)
printf("Board::moveToReach: moveNo %d => %d ?!\n",
_moveNo, b->moveNo());
return m;
}
/* only time left for player can have decreased */
int opponent = (color == color1) ? color2 : color1;
if (_msecsToPlay[opponent] != b->msecsToPlay(opponent)) {
if (_verbose)
printf("Board::moveToReach: Opponent time changed ?!\n");
return m;
}
if (_msecsToPlay[color] < b->msecsToPlay(color)) {
if (_verbose)
printf("Board::moveToReach: Player time increased ?!\n");
return m;
}
}
/* detect move drawn */
MoveList l;
generateMoves(l);
if (_verbose) {
printf("Board::moveToReach - %d allowed moves:\n",
l.getLength());
Move found;
int type = Move::none;
while(l.getNext(m, Move::maxMoveType)) {
playMove(m);
bool isSame = hasSameFields(b);
takeBack();
if (isSame) found = m;
if (m.type != type) {
type = m.type;
printf(" %s:\n", m.typeName());
}
printf(" %s%s\n", m.name(), isSame ? " <== Choosen":"");
}
m = found;
}
else {
while(l.getNext(m, Move::maxMoveType)) {
playMove(m);
bool isSame = hasSameFields(b);
takeBack();
if (isSame) break;
}
}
return m;
}
bool Board::hasSameFields(Board* b)
{
int f, actField;
for(f=0;f<RealFields;f++) {
actField = order[f];
if ( field[actField] != (*b)[actField] )
return false;
}
return true;
}
void Board::playMove(const Move& m, int msecs)
{
int f, dir, dir2;
int opponent = (color == color1) ? color2:color1;
CHECK( isConsistent() );
if (++storedLast == MvsStored) storedLast = 0;
/* Buffer full -> delete oldest entry */
if (storedLast == storedFirst)
if (++storedFirst == MvsStored) storedFirst = 0;
storedMove[storedLast] = m;
f = m.field;
CHECK( (m.type >= 0) && (m.type < Move::none));
CHECK( field[f] == color );
field[f] = free;
dir = direction[m.direction];
switch(m.type) {
case Move::out2: /* (c c c o o |) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == opponent );
CHECK( field[f + 4*dir] == opponent );
CHECK( field[f + 5*dir] == out );
field[f + 3*dir] = color;
break;
case Move::out1with3: /* (c c c o |) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == opponent );
CHECK( field[f + 4*dir] == out );
field[f + 3*dir] = color;
break;
case Move::move3: /* (c c c .) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == free );
field[f + 3*dir] = color;
break;
case Move::out1with2: /* (c c o |) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == opponent );
CHECK( field[f + 3*dir] == out );
field[f + 2*dir] = color;
break;
case Move::move2: /* (c c .) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == free );
field[f + 2*dir] = color;
break;
case Move::push2: /* (c c c o o .) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == opponent );
CHECK( field[f + 4*dir] == opponent );
CHECK( field[f + 5*dir] == free );
field[f + 3*dir] = color;
field[f + 5*dir] = opponent;
break;
case Move::left3:
dir2 = direction[m.direction-1];
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + dir2] == free );
CHECK( field[f + dir+dir2] == free );
CHECK( field[f + 2*dir+dir2] == free );
field[f+dir2] = color;
field[f+=dir] = free;
field[f+dir2] = color;
field[f+=dir] = free;
field[f+dir2] = color;
break;
case Move::right3:
dir2 = direction[m.direction+1];
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + dir2] == free );
CHECK( field[f + dir+dir2] == free );
CHECK( field[f + 2*dir+dir2] == free );
field[f+dir2] = color;
field[f+=dir] = free;
field[f+dir2] = color;
field[f+=dir] = free;
field[f+dir2] = color;
break;
case Move::push1with3: /* (c c c o .) => (. c c c o) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == opponent );
CHECK( field[f + 4*dir] == free );
field[f + 3*dir] = color;
field[f + 4*dir] = opponent;
break;
case Move::push1with2: /* (c c o .) => (. c c o) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == opponent );
CHECK( field[f + 3*dir] == free );
field[f + 2*dir] = color;
field[f + 3*dir] = opponent;
break;
case Move::left2:
dir2 = direction[m.direction-1];
CHECK( field[f + dir] == color );
CHECK( field[f + dir2] == free );
CHECK( field[f + dir+dir2] == free );
field[f+dir2] = color;
field[f+=dir] = free;
field[f+dir2] = color;
break;
case Move::right2:
dir2 = direction[m.direction+1];
CHECK( field[f + dir] == color );
CHECK( field[f + dir2] == free );
CHECK( field[f + dir+dir2] == free );
field[f+dir2] = color;
field[f+=dir] = free;
field[f+dir2] = color;
break;
case Move::move1: /* (c .) => (. c) */
CHECK( field[f + dir] == free );
field[f + dir] = color;
break;
default:
break;
}
if (m.isOutMove()) {
if (color == color1)
color2Count--;
else
color1Count--;
}
/* adjust move number and time */
_moveNo++;
if ((_msecsToPlay[color]>0) && (msecs>0)) {
if (_msecsToPlay[color] > msecs)
_msecsToPlay[color] -= msecs;
else
_msecsToPlay[color] = 0;
}
/* change actual color */
color = opponent;
CHECK( isConsistent() );
}
bool Board::takeBack()
{
int f, dir, dir2;
int opponent = color;
Move& m = storedMove[storedLast];
CHECK( isConsistent() );
if (storedFirst == storedLast) return false;
/* change actual color */
color = (color == color1) ? color2:color1;
if (m.isOutMove()) {
if (color == color1)
color2Count++;
else
color1Count++;
}
f = m.field;
CHECK( field[f] == free );
field[f] = color;
dir = direction[m.direction];
switch(m.type) {
case Move::out2: /* (. c c c o |) => (c c c o o |) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == color );
CHECK( field[f + 4*dir] == opponent );
CHECK( field[f + 5*dir] == out );
field[f + 3*dir] = opponent;
break;
case Move::out1with3: /* (. c c c |) => (c c c o |) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == color );
CHECK( field[f + 4*dir] == out );
field[f + 3*dir] = opponent;
break;
case Move::move3: /* (. c c c) => (c c c .) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == color );
field[f + 3*dir] = free;
break;
case Move::out1with2: /* (. c c | ) => (c c o |) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == out );
field[f + 2*dir] = opponent;
break;
case Move::move2: /* (. c c) => (c c .) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
field[f + 2*dir] = free;
break;
case Move::push2: /* (. c c c o o) => (c c c o o .) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == color );
CHECK( field[f + 4*dir] == opponent );
CHECK( field[f + 5*dir] == opponent );
field[f + 3*dir] = opponent;
field[f + 5*dir] = free;
break;
case Move::left3:
dir2 = direction[m.direction-1];
CHECK( field[f + dir] == free );
CHECK( field[f + 2*dir] == free );
CHECK( field[f + dir2] == color );
CHECK( field[f + dir+dir2] == color );
CHECK( field[f + 2*dir+dir2] == color );
field[f+dir2] = free;
field[f+=dir] = color;
field[f+dir2] = free;
field[f+=dir] = color;
field[f+dir2] = free;
break;
case Move::right3:
dir2 = direction[m.direction+1];
CHECK( field[f + dir] == free );
CHECK( field[f + 2*dir] == free );
CHECK( field[f + dir2] == color );
CHECK( field[f + dir+dir2] == color );
CHECK( field[f + 2*dir+dir2] == color );
field[f+dir2] = free;
field[f+=dir] = color;
field[f+dir2] = free;
field[f+=dir] = color;
field[f+dir2] = free;
break;
case Move::push1with3: /* (. c c c o) => (c c c o .) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == color );
CHECK( field[f + 4*dir] == opponent );
field[f + 3*dir] = opponent;
field[f + 4*dir] = free;
break;
case Move::push1with2: /* (. c c o) => (c c o .) */
CHECK( field[f + dir] == color );
CHECK( field[f + 2*dir] == color );
CHECK( field[f + 3*dir] == opponent );
field[f + 2*dir] = opponent;
field[f + 3*dir] = free;
break;
case Move::left2:
dir2 = direction[m.direction-1];
CHECK( field[f + dir] == free );
CHECK( field[f + dir2] == color );
CHECK( field[f + dir+dir2] == color );
field[f+dir2] = free;
field[f+=dir] = color;
field[f+dir2] = free;
break;
case Move::right2:
dir2 = direction[m.direction+1];
CHECK( field[f + dir] == free );
CHECK( field[f + dir2] == color );
CHECK( field[f + dir+dir2] == color );
field[f+dir2] = free;
field[f+=dir] = color;
field[f+dir2] = free;
break;
case Move::move1: /* (. c) => (c .) */
CHECK( field[f + dir] == color );
field[f + dir] = free;
break;
default:
break;
}
if (--storedLast < 0) storedLast = MvsStored-1;
/* adjust move number. Time is intentionally not reset */
_moveNo--;
CHECK( isConsistent() );
return true;
}
int Board::movesStored()
{
int c = storedLast - storedFirst;
if (c<0) c+= MvsStored;
return c;
}
/** validState
*
* Check for a valid board position to play from:
* (1) Number of balls for each color has to be between 9 and 14
* (2) There must be a move possible for actual color
*/
int Board::validState()
{
MoveCounter mc;
int c1 = 0, c2 = 0;
int i,j, moveCount, res;
int color = actColor();
for(i=0;i<AllFields;i++) {
j=field[i];
if (j == color1) c1++;
if (j == color2) c2++;
if (j == color)
countFrom( i, color, mc);
}
color1Count = c1;
color2Count = c2;
moveCount = mc.moveSum();
if (c1==0 && c2==0)
res = empty;
// impossible token counts
else if (c1>14 || c2>14 || (c1<9 && c2<9))
res = invalid;
else if (c1<9)
res = win2;
else if (c2<9)
res = win1;
// counts are in valid range...
else if (moveCount>0) {
if (color == color1) {
if (_msecsToPlay[color1]>0 && _msecsToPlay[color2]<=0)
res = timeout2;
else
res = valid1;
}
else {
if (_msecsToPlay[color2]>0 && _msecsToPlay[color1]<=0)
res = timeout1;
else
res = valid2;
}
}
// color which has to draw can not do any move... win for opponent!
else if (color == color1)
res = win2;
else
res = win1;
#ifdef MYTRACE
if (spyLevel>2) {
indent(spyDepth);
printf("Valid: %s (Color1 %d, Color2 %d, moveCount of %d: %d)\n",
(res == empty) ? "empty" : (res==valid) ? "valid":"invalid",
c1,c2,color,moveCount);
}
#endif
return res;
}
char* Board::stateDescription(int s)
{
switch(s) {
case empty: return "Empty board";
case invalid: return "Invalid board";
case valid1: return "O about to move...";
case valid2: return "X about to move...";
case timeout1: return "O timed out. X wins!";
case timeout2: return "X timed out. O wins!";
case win1: return "O wins the game!";
case win2: return "X wins the game!";
default: break;
}
return "Unknown state?";
}
bool Board::isConsistent()
{
int c1 = 0, c2 = 0;
int i,j;
for(i=0;i<RealFields;i++) {
j=field[order[i]];
if (j == color1) c1++;
if (j == color2) c2++;
}
return (color1Count == c1 && color2Count == c2);
}
void Board::setSearchStrategy(SearchStrategy* ss)
{
_ss = ss;
}
void Board::setDepth(int d)
{
if (!_ss) return;
_ss->setMaxDepth(d+1);
}
Move& Board::bestMove()
{
static Move best;
best = _ss->bestMove(this);
return best;
}
Move& Board::nextMove()
{
return _ss->nextMove();
}
void Board::stopSearch()
{
_ss->stopSearch();
}
Move Board::randomMove()
{
Move m;
MoveList list;
generateMoves(list);
int l = list.getLength();
int j = (::rand() % l) +1;
while(j != 0) {
list.getNext(m, Move::none);
j--;
}
return m;
}
void Board::print()
{
printf( getState() );
}
/* Returns a board human readable board representation.
* The returned string will be overwritten in later calls.
*/
char* Board::getState()
{
static char b[1024];
int pos = 0;
int row,i;
char spaces[]=" ";
const char *z[]={". ","O ","X ", "o ", "x "};
pos = sprintf(b, "\n");
if (_moveNo>=0) {
pos += sprintf(b+pos, "#%d", _moveNo);
pos += sprintf(b+pos, " O: %d", color1Count);
if (_msecsToPlay[color1]>0)
pos += sprintf(b+pos, " (%d.%03d s)",
_msecsToPlay[color1]/1000, _msecsToPlay[color1]%1000);
pos += sprintf(b+pos, ", X: %d", color2Count);
if (_msecsToPlay[color2]>0)
pos += sprintf(b+pos, " (%d.%03d s)",
_msecsToPlay[color2]/1000, _msecsToPlay[color2]%1000);
pos += sprintf(b+pos, "\n");
}
pos += sprintf(b+pos, " -----------\n");
for(row=0;row<4;row++) {
pos += sprintf(b+pos, "%s/ ",spaces+row);
for(i=0;i<5+row;i++)
pos += sprintf(b+pos, "%s",z[field[row*11+12+i]]);
pos += sprintf(b+pos, "\\\n");
}
pos += sprintf(b+pos, " | ");
for(i=0;i<9;i++)
pos += sprintf(b+pos, "%s", z[field[56+i]]);
pos += sprintf(b+pos, "|\n");
for(row=0;row<4;row++) {
pos += sprintf(b+pos, "%s\\ ",spaces+3-row);
for(i=0;i<8-row;i++)
pos += sprintf(b+pos, "%s",z[field[68+row*12+i]]);
pos += sprintf(b+pos, "/\n");
}
pos += sprintf(b+pos, " -----------\n");
return b;
}
bool Board::setState(char* s)
{
int row = 0, column = 0;
bool found = false;
color1Count = 0;
color2Count = 0;
_msecsToPlay[color1] = 0;
_msecsToPlay[color2] = 0;
if (s == 0) return false;
while(*s) {
if (*s == '#') {
int m = 0;
int color = -1;
s++;
// parse "#<moveNo> - [O: <count> / <secsToPlay>, X:]"
while((*s >= '0') && (*s <= '9')) m = 10*m + (*s++ -'0');
_moveNo = m;
while(*s) {
if (*s == '\n') break;
if (*s == 'O') { color = color1; }
if (*s == 'X') { color = color2; }
if ((*s == '(') && (color>-1)) {
s++;
int secs=0, msecs=0;
while(*s==' ') s++;
while((*s >= '0') && (*s <= '9')) secs = 10*secs + (*s++ -'0');
if (*s=='.') {
int val = 100;
s++;
while((*s >= '0') && (*s <= '9')) {
msecs += val * (*s++ -'0');
val /= 10;
}
}
_msecsToPlay[color] = 1000 * secs + msecs;
color = -1;
}
s++;
}
}
if (row*11+12+column > AllFields) break;
if (*s == '.' || *s == 'X' || *s == 'O' ||
*s == 'x' || *s == 'o') {
found = true;
field[row*11+12+column] =
(*s == 'O') ? color1 :
(*s == 'o') ? color1 :
(*s == 'X') ? color2 :
(*s == 'x') ? color2 : free;
if (field[row*11+12+column] == color1) color1Count++;
if (field[row*11+12+column] == color2) color2Count++;
column++;
}
if (found && (*s == '\n')) {
row++;
if (row < 5) column = 0;
else column = row-4;
if (row >8) break;
}
s++;
}
if (row <9) return false;
color = ((_moveNo%2)==0) ? color1 : color2;
return true;
}
void Board::setSpyLevel(int level)
{
spyLevel = level;
}
/*
* Classes
* - Board: represents a game state
* - EvalScheme: evaluation scheme
*
* (c) 1997-2005, Josef Weidendorfer
*/
#ifndef BOARD_H
#define BOARD_H
#include "move.h"
class SearchStrategy;
class Evaluator;
/**
* Class MoveCounter
*
* Helper class for board characteristics:
* Counter for move types and connectivity
* See Board::countFrom().
*/
class MoveCounter
{
public:
enum InARowType { inARow2 = 0, inARow3, inARow4, inARow5, inARowCount };
MoveCounter();
void init();
int moveCount(int t) { return _moveCount[t]; }
void incType(int t) { _moveCount[t]++; }
int moveSum();
int rowCount(int r) { return _rowCount[r]; }
void incRow(int r) { _rowCount[r]++; }
private:
int _moveCount[Move::typeCount];
int _rowCount[inARowCount];
};
/**
* Board: represents a game state
*
* Includes methods for
* - play/take back moves
* - generate allowed moves
* - calculate rating for position
* - search for best move
*/
class Board
{
friend class Evaluator;
public:
Board();
~Board() {};
/* different states of one field */
enum {
out = 10, free = 0,
color1, color2, color1bright, color2bright
};
enum { AllFields = 121, /* visible + ring of unvisible around */
RealFields = 61, /* number of visible fields */
MvsStored = 100 };
enum { empty=0,
valid1, // valid state with color1 to draw
valid2, // valid state with color2 to draw
timeout1, // time out for color1 -> win for color2
timeout2, // time out for color2 -> win for color1
win1, // color1 won
win2, // color2 won
invalid };
/* fill Board with defined values */
void begin(int startColor); /* start of a game */
void clear(); /* empty board */
/* fields can't be changed ! */
int operator[](int no) const;
int actColor() const
{ return color; }
/* helper in evaluation: calculate move type counts */
void countFrom(int startField, int color, MoveCounter&);
/* Generate list of allowed moves for player with <color>
* Returns a calculated value for actual position */
void generateMoves(MoveList& list);
/* Check if a game position is reachable from the current one.
* If <fuzzy> is false, this check includes times and move number.
* Returns move which was played. Returns move of type Move::none if not.
*/
Move moveToReach(Board*, bool fuzzy);
/** Check if another board has same tokens set */
bool hasSameFields(Board*);
/* Play the given move.
* Played moves can be taken back (<MvsStored> moves are remembered)
* Time to play is adjusted if msecs > 0.
*
* Warning: Only moves that are generated with Board::generateMoves()
* should be passed. If the move cannot be played, an assertion is raised.
*/
void playMove(const Move& m, int msecs = 0);
bool takeBack(); /* if not remembered, do nothing */
int movesStored(); /* return how many moves are remembered */
Move& lastMove()
{ return storedMove[storedLast]; }
void showHist();
/* Evaluator to use */
void setEvaluator(Evaluator* ev) { _ev = ev; }
void setActColor(int c) { color=c; }
void setColor1Count(int c) { color1Count = c; }
void setColor2Count(int c) { color2Count = c; }
void setField(int i, int v) { field[i] = v; }
void setSpyLevel(int);
int getColor1Count() { return color1Count; }
int getColor2Count() { return color2Count; }
bool isValid() { return (color1Count>8 && color2Count>8); }
/* Is this position valid, a winner position or invalid? */
int validState();
/* returns a string for the valid state */
static char* stateDescription(int);
/* Check that color1Count & color2Count is consistent with board */
bool isConsistent();
/* Searching best move */
void setSearchStrategy(SearchStrategy* ss);
void setDepth(int d);
Move& bestMove();
/* next move in prinipal variation */
Move& nextMove();
Move randomMove();
void stopSearch();
void setMoveNo(int n) { _moveNo = n; }
void setMSecsToPlay(int c, int s) { _msecsToPlay[c] = s; }
int moveNo() { return _moveNo; }
int msecsToPlay(int c) { return _msecsToPlay[c]; }
/* Readable ASCII representation */
char* getState();
/* Returns true if new state was set */
bool setState(char*);
void setVerbose(int v) { _verbose = v; }
void updateSpy(bool b) { bUpdateSpy = b; }
/* simple terminal view of position */
void print();
static int fieldDiffOfDir(int d) { return direction[d]; }
private:
void setFieldValues();
/* helper function for generateMoves */
void generateFieldMoves(int, MoveList&);
// random seed
int seed;
int field[AllFields]; /* actual board */
int color1Count, color2Count;
int color; /* actual color */
Move storedMove[MvsStored]; /* stored moves */
int storedFirst, storedLast; /* stored in ring puffer manner */
int _moveNo; /* move number in current game */
int _msecsToPlay[3]; /* time in seconds to play */
bool show, bUpdateSpy;
int spyLevel, spyDepth;
SearchStrategy* _ss;
Evaluator* _ev;
int _verbose;
/* constant arrays */
static int startBoard[AllFields];
static int order[RealFields];
static int direction[8];
public:
/* for fast evaluation */
int* fieldArray() { return field; }
};
inline int Board::operator[](int no) const
{
return (no<12 || no>120) ? out : field[no];
}
#endif
/**
* EvalScheme and Evaluator
*/
#include "eval.h"
// Default Values
static int defaultRingValue[] = { 45, 35, 25, 10, 0 };
static int defaultRingDiff[] = { 0, 10, 10, 8, 5 };
static int defaultStoneValue[]= { 0,-800,-1800,-3000,-4400,-6000 };
static int defaultMoveValue[Move::typeCount] = { 40,30,30, 15,14,13,
5,5,5, 2,2,2, 1 };
static int defaultInARowValue[MoveCounter::inARowCount]= { 2, 5, 4, 3 };
/**
* Constructor: Set Default values
*/
EvalScheme::EvalScheme(char* file)
{
setDefaults();
read(file);
}
void EvalScheme::setDefaults()
{
for(int i=0;i<6;i++)
_stoneValue[i] = defaultStoneValue[i];
for(int i=0;i<Move::typeCount;i++)
_moveValue[i] = defaultMoveValue[i];
for(int i=0;i<MoveCounter::inARowCount;i++)
_inARowValue[i] = defaultInARowValue[i];
for(int i=0;i<5;i++)
_ringValue[i] = defaultRingValue[i];
for(int i=0;i<5;i++)
_ringDiff[i] = defaultRingDiff[i];
}
void EvalScheme::read(char* file)
{
if (file == 0 || *file == 0) return;
// TODO
}
void EvalScheme::save(char* file)
{
// TODO
}
void EvalScheme::setRingValue(int ring, int value)
{
if (ring >=0 && ring <5)
_ringValue[ring] = value;
}
void EvalScheme::setRingDiff(int ring, int value)
{
if (ring >=1 && ring <5)
_ringDiff[ring] = value;
}
void EvalScheme::setStoneValue(int stoneDiff, int value)
{
if (stoneDiff>0 && stoneDiff<6)
_stoneValue[stoneDiff] = value;
}
void EvalScheme::setMoveValue(int type, int value)
{
if (type>=0 && type<Move::typeCount)
_moveValue[type] = value;
}
void EvalScheme::setInARowValue(int stones, int value)
{
if (stones>=0 && stones<MoveCounter::inARowCount)
_inARowValue[stones] = value;
}
/// Evaluator
int Evaluator::fieldValue[61];
Evaluator::Evaluator()
{
_evalScheme = 0;
}
void Evaluator::setEvalScheme(EvalScheme* scheme)
{
if (!scheme)
scheme = new EvalScheme(0);
_evalScheme = scheme;
setFieldValues();
}
void Evaluator::setFieldValues()
{
if (!_evalScheme) return;
int i, j = 0, k = 59;
int ringValue[5], ringDiff[5];
for(i=0;i<5;i++) {
ringDiff[i] = _evalScheme->ringDiff(i);
ringValue[i] = _evalScheme->ringValue(i);
if (ringDiff[i]<1) ringDiff[i]=1;
}
fieldValue[0] = ringValue[0];
for(i=1;i<7;i++)
fieldValue[i] = ringValue[1] + ((j+=k) % ringDiff[1]);
for(i=7;i<19;i++)
fieldValue[i] = ringValue[2] + ((j+=k) % ringDiff[2]);
for(i=19;i<37;i++)
fieldValue[i] = ringValue[3] + ((j+=k) % ringDiff[3]);
for(i=37;i<61;i++)
fieldValue[i] = ringValue[4] + ((j+=k) % ringDiff[4]);
}
void Evaluator::setBoard(Board* b)
{
_board = b;
field = b->fieldArray();
}
/* Calculate a evaluation for actual position
*
* A higher value means a better position for opponent
* NB: This means a higher value for better position of
* 'color before last move'
*/
int Evaluator::calcEvaluation(Board* b)
{
setBoard(b);
int color = b->actColor();
if (!_evalScheme) {
// Use default values if not set
setEvalScheme();
}
MoveCounter cColor, cOpponent;
int f,i,j;
/* different evaluation types */
int fieldValueSum=0, stoneValueSum=0;
int moveValueSum=0, inARowValueSum=0;
int valueSum;
/* First check simple winner condition */
int color1Count = _board->getColor1Count();
int color2Count = _board->getColor2Count();
if (color1Count <9)
valueSum = (color==color1) ? 16000 : -16000;
else if (color2Count <9)
valueSum = (color==color2) ? 16000 : -16000;
else {
/* Calculate fieldValueSum and count move types and connectivity */
for(i=0;i<RealFields;i++) {
j=field[f=Board::order[i]];
if (j == free) continue;
if (j == color) {
b->countFrom( f, j, cColor );
fieldValueSum -= fieldValue[i];
}
else {
b->countFrom( f, j, cOpponent );
fieldValueSum += fieldValue[i];
}
}
/* If color can't do any moves, opponent wins... */
if (cColor.moveSum() == 0)
valueSum = 16000;
else {
for(int t=0;t < Move::typeCount;t++)
moveValueSum += _evalScheme->moveValue(t) *
(cOpponent.moveCount(t) - cColor.moveCount(t));
for(int i=0;i < MoveCounter::inARowCount;i++)
inARowValueSum += _evalScheme->inARowValue(i) *
(cOpponent.rowCount(i) - cColor.rowCount(i));
if (color == color2)
stoneValueSum = _evalScheme->stoneValue(14 - color1Count) -
_evalScheme->stoneValue(14 - color2Count);
else
stoneValueSum = _evalScheme->stoneValue(14 - color2Count) -
_evalScheme->stoneValue(14 - color1Count);
valueSum = fieldValueSum + moveValueSum +
inARowValueSum + stoneValueSum;
}
}
#ifdef MYTRACE
if (spyLevel>2) {
indent(spyDepth);
printf("Eval %d (field %d, move %d, inARow %d, stone %d)\n",
valueSum, fieldValueSum, moveValueSum,
inARowValueSum, stoneValueSum );
}
#endif
return valueSum;
}
void Evaluator::changeEvaluation()
{
int i,tmp;
/* innermost ring */
tmp=fieldValue[1];
for(i=1;i<6;i++)
fieldValue[i] = fieldValue[i+1];
fieldValue[6] = tmp;
tmp=fieldValue[7];
for(i=7;i<18;i++)
fieldValue[i] = fieldValue[i+1];
fieldValue[18] = tmp;
tmp=fieldValue[19];
for(i=19;i<36;i++)
fieldValue[i] = fieldValue[i+1];
fieldValue[36] = tmp;
/* the outermost ring */
tmp=fieldValue[37];
for(i=37;i<60;i++)
fieldValue[i] = fieldValue[i+1];
fieldValue[60] = tmp;
}
/**
* EvalScheme and Evaluator
*
* A board evaluation scheme using a combination of 3 evaluations:
* - Token difference
* - Place
* - Movability / Connectivity
*
* Coefficients used for these evaluations are variable.
*
* The constructor gets a name, and tries to read the coefficients
* from a configuration file, if nothing found, use default values
*/
#ifndef EVAL_H
#define EVAL_H
#include "board.h"
class EvalScheme
{
public:
EvalScheme(char*);
~EvalScheme() {}
void setDefaults();
void read(char* file);
void save(char* file);
void setRingValue(int ring, int value);
void setRingDiff(int ring, int value);
void setStoneValue(int stoneDiff, int value);
void setMoveValue(int type, int value);
void setInARowValue(int stones, int value);
int ringValue(int r) { return (r>=0 && r<5) ? _ringValue[r] : 0; }
int ringDiff(int r) { return (r>0 && r<5) ? _ringDiff[r] : 0; }
int stoneValue(int s) { return (s>0 && s<6) ? _stoneValue[s] : 0; }
int moveValue(int t)
{ return (t>=0 && t<Move::typeCount) ? _moveValue[t] : 0;}
int inARowValue(int s)
{ return (s>=0 && s<MoveCounter::inARowCount) ? _inARowValue[s]:0; }
private:
int _ringValue[5], _ringDiff[5];
int _stoneValue[6], _moveValue[Move::none];
int _inARowValue[MoveCounter::inARowCount];
};
class Evaluator
{
public:
/* different states of one field */
enum {
out = 10, free = 0,
color1, color2, color1bright, color2bright
};
enum { AllFields = 121, /* visible + ring of unvisible around */
RealFields = 61, /* number of visible fields */
MvsStored = 100 };
Evaluator();
/* Evaluation Scheme to use */
void setEvalScheme( EvalScheme* scheme = 0);
EvalScheme* evalScheme() { return _evalScheme; }
void setFieldValues();
int minValue() { return -15000; }
int maxValue() { return 15000; }
/* Calculate a value for actual position
* (greater if better for color1) */
int calcEvaluation(Board*);
/* Evalution is based on values which can be changed
* a little (so computer's moves aren't always the same) */
void changeEvaluation();
void setBoard(Board*);
private:
Board* _board;
EvalScheme* _evalScheme;
int* field;
/* ratings; semi constant - are rotated by changeRating() */
static int fieldValue[Board::RealFields];
};
#endif
/*
* Classes
* - Move: a move on the game board
* - MoveTypeCounter, InARowCounter: evaluation helpers
* - MoveList: stores list of moves allowed from a position
* - Variation: stores move sequences
*
* (c) 1997-2005, Josef Weidendorfer
*/
#include <assert.h>
#include <stdio.h>
#include "move.h"
#include "board.h"
static const char* nameOfDir(int dir)
{
dir = dir % 6;
return
(dir == 1) ? "Right" :
(dir == 2) ? "RightDown" :
(dir == 3) ? "LeftDown" :
(dir == 4) ? "Left" :
(dir == 5) ? "LeftUp" :
(dir == 0) ? "RightUp" : "??";
}
static char* nameOfPos(int p)
{
static char tmp[3];
tmp[0] = (char)('A' + (p-12)/11);
tmp[1] = (char)('1' + (p-12)%11);
tmp[2] = 0;
return tmp;
}
/// Move
char* Move::name() const
{
static char s[30];
int pos;
/* sideway moves... */
if (type == left3 || type == right3) {
int f1, f2, df;
f1 = f2 = field;
df = 2* Board::fieldDiffOfDir(direction);
if (df > 0)
f2 += df;
else
f1 += df;
pos = sprintf(s, "%s-", nameOfPos( f1 ));
const char* dir = (type == left3) ? nameOfDir(direction-1): nameOfDir(direction+1);
sprintf(s+pos, "%s/%s", nameOfPos( f2 ), dir);
}
else if ( type == left2 || type == right2) {
int f1, f2, df;
f1 = f2 = field;
df = Board::fieldDiffOfDir(direction);
if (df > 0)
f2 += df;
else
f1 += df;
pos = sprintf(s, "%s-", nameOfPos( f1 ));
const char* dir = (type == left2) ? nameOfDir(direction-1): nameOfDir(direction+1);
sprintf(s+pos, "%s/%s", nameOfPos( f2 ), dir);
}
else if (type == none) {
return "??";
}
else {
int p = sprintf(s, "%s/%s",
nameOfPos( field ), nameOfDir(direction));
if (type<3) sprintf(s+p,"/Out");
else if (type<6) sprintf(s+p,"/Push");
}
return s;
}
char* Move::typeName() const
{
switch(type) {
case out2: return "Out, pushing 2 opponents with 3";
case out1with3: return "Out, pushing 1 opponent with 3";
case out1with2: return "Out, pushing 1 opponent with 2";
case push2: return "Pushing 2 opponents with 3";
case push1with3: return "Pushing 1 opponent with 3";
case push1with2: return "Pushing 1 opponent with 2";
case move3: return "Moving 3 in a row";
case left3: return "Moving 3 left sideways";
case right3: return "Moving 3 right sideways";
case left2: return "Moving 2 left sideways";
case right2: return "Moving 2 right sideways";
case move2: return "Moving 2 in a row";
case move1: return "Moving 1";
default:
break;
}
return "Invalid type";
}
void Move::print() const
{
printf("%s", name() );
}
/// MoveList
MoveList::MoveList()
{
clear();
}
void MoveList::clear()
{
int i;
for(i=0;i<Move::typeCount;i++)
first[i] = actual[i] = -1;
nextUnused = 0;
actualType = -1;
}
void MoveList::insert(Move m)
{
int t = m.type;
/* valid and possible ? */
if (t <0 || t >= Move::typeCount) return;
//if (nextUnused == MaxMoves) return;
assert( nextUnused < MaxMoves );
/* adjust queue */
if (first[t] == -1) {
first[t] = last[t] = nextUnused;
}
else {
assert( last[t] < nextUnused );
next[last[t]] = nextUnused;
last[t] = nextUnused;
}
next[nextUnused] = -1;
move[nextUnused] = m;
nextUnused++;
}
bool MoveList::isElement(int f)
{
int i;
for(i=0; i<nextUnused; i++)
if (move[i].field == f)
return true;
return false;
}
bool MoveList::isElement(Move &m, int startType, bool del)
{
int i;
for(i=0; i<nextUnused; i++) {
Move& mm = move[i];
if (mm.field != m.field)
continue;
/* if direction is supplied it has to match */
if ((m.direction > 0) && (mm.direction != m.direction))
continue;
/* if type is supplied it has to match */
if ((m.type != Move::none) && (m.type != mm.type))
continue;
if (m.type == mm.type) {
/* exact match; eventually supply direction */
m.direction = mm.direction;
if (del) mm.type = Move::none;
return true;
}
switch(mm.type) {
case Move::left3:
case Move::right3:
if (startType == start3 || startType == all) {
m.type = mm.type;
m.direction = mm.direction;
if (del) mm.type = Move::none;
return true;
}
break;
case Move::left2:
case Move::right2:
if (startType == start2 || startType == all) {
m.type = mm.type;
m.direction = mm.direction;
if (del) mm.type = Move::none;
return true;
}
break;
default:
if (startType == start1 || startType == all) {
/* unexact match: supply type */
m.type = mm.type;
m.direction = mm.direction;
if (del) mm.type = Move::none;
return true;
}
}
}
return false;
}
bool MoveList::getNext(Move& m, int maxType)
{
if (actualType == Move::typeCount) return false;
while(1) {
while(actualType < 0 || actual[actualType] == -1) {
actualType++;
if (actualType == Move::typeCount) return false;
actual[actualType] = first[actualType];
if (actualType > maxType) return false;
}
m = move[actual[actualType]];
actual[actualType] = next[actual[actualType]];
if (m.type != Move::none) break;
}
return true;
}
int MoveList::count(int maxType)
{
int c = 0;
int type = actualType;
int act = 0;
if (type>=0) act = actual[type];
while(1) {
while(type < 0 || act == -1) {
type++;
if (type == Move::typeCount) return c;
act = first[type];
if (type > maxType) return c;
}
c++;
act = next[act];
}
return c;
}
/// Variation
void Variation::clear(int d)
{
int i,j;
for(i=0;i<maxDepth;i++)
for(j=0;j<maxDepth;j++) {
move[i][j].type = Move::none;
}
actMaxDepth = (d<maxDepth) ? d:maxDepth-1;
}
void Variation::update(int d, Move& m)
{
int i;
if (d>actMaxDepth) return;
for(i=d+1;i<=actMaxDepth;i++) {
move[d][i]=move[d+1][i];
move[d+1][i].type = Move::none;
}
move[d][d]=m;
}
/*
* Classes
* - Move: a move on the game board
* - MoveTypeCounter, InARowCounter: evaluation helpers
* - MoveList: stores list of moves allowed from a position
* - Variation: stores move sequences
*
* (c) 1997-2005, Josef Weidendorfer
*/
#ifndef MOVE_H
#define MOVE_H
/**
* Class Move
*
* A move on the game board.
* A move is given by a start position number on the board
* (for board numbering, see board.h), a direction (out of 6),
* and the type of the move. Type includes the number of own
* and opponents tokens taken part in the move, and side-way
* moves.
*/
class Move
{
public:
/* Directions */
enum { Right=1, RightDown, LeftDown, Left, LeftUp, RightUp };
/* Type of move: Moves are searched in this order */
enum MoveType { out2 = 0, out1with3, out1with2, push2,
push1with3, push1with2, move3, left3, right3,
left2, right2, move2, move1, none };
/* Constants to specify move type ranges. For this to work,
* the enum order in MoveType must not be changed!
*/
enum { typeCount = none,
maxOutType = out1with2,
maxPushType = push1with2,
maxMoveType = move1 };
/* Constructor for an invalid move */
Move() { type = none; field = 0; direction = 0; }
/* Move starting at f, direction d, and Type t */
Move(short f, char d, MoveType t)
{ field = f; direction = d, type = t; }
/* Does this move push out an opponents token? */
bool isOutMove() const { return type <= out1with2; }
/* Does this move push opponent tokens? */
bool isPushMove() const { return type <= push1with2; }
/* for communication to outer world */
char* name() const;
char* typeName() const;
/* debugging output */
void print() const;
/* Allow public R/W access... */
short field;
unsigned char direction;
MoveType type;
};
/**
* Class MoveList
*
* Stores a fixed number of moves (for efficince)
* <getNext> returns reference of next move ordered according to type
* <insert> does nothing if there isn't enough free space
*
* Recommend usage (* means 0 or more times):
* [ clear() ; insert() * ; isElement() * ; getNext() * ] *
*/
class MoveList
{
public:
MoveList();
enum { MaxMoves = 150 };
/* for isElement: search for moves starting with 1/2/3 fields */
enum { all , start1, start2, start3 };
void clear();
void insert(Move);
bool isElement(int f);
bool isElement(Move&, int startType, bool del=false);
void insert(short f, char d, Move::MoveType t)
{ insert( Move(f,d,t) ); }
int getLength()
{ return nextUnused; }
int count(int maxType = Move::typeCount);
/**
* Get next move from the list into the Move instance
* given by first arg which is passed by reference.
*
* Move types are sorted, and you can specify the maximal
* type allowed to be returned. Default is to return all moves.
*
* Return false if no more moves (with given type constrain)
*/
bool getNext(Move&, int maxType = Move::none);
private:
Move move[MaxMoves];
int next[MaxMoves];
int first[Move::typeCount];
int last[Move::typeCount];
int actual[Move::typeCount];
int nextUnused, actualType;
};
/**
* Stores best move sequence = principal variation
*
* Implementation uses upper left triangle of a matrix,
* with row 0 holding best sequence found so far from
* real current game position, row 1 holding best sequence
* starting from currently searched depth 1 in game tree,
* row 2 from depth 2 and so on.
*
* Uses:
* - A new best move sequence at search depth d was found.
* copy current move of depth d into [d][0], and the rest from row d+1.
* - Read principal variation on starting a new alpha/beta search.
* This heuristic is assumed to lead to a lot of cutoffs happening.
* - Read finally found best move from [0][0]
* - Allow for computer hints to the opponent by looking at [0][1]
*/
class Variation
{
public:
enum { maxDepth = 10 };
Variation() { clear(1); }
/* Does the best sequence have a move for depth d ? */
bool hasMove(int d)
{ return (d>actMaxDepth) ?
false : (move[0][d].type != Move::none); }
/* Get move at index i from best move chain */
Move& operator[](int i)
{ return (i<0 || i>=maxDepth) ? move[0][0] : move[0][i]; }
/* Get move chain at depth d */
Move* chain(int d)
{ return (d<0 || d>=maxDepth) ? &(move[0][0]) : &(move[d][d]); }
/* Update best move from depth d, starting with move m at this depth */
void update(int d, Move& m);
/* Clear sequence storage for moves from depth d */
void clear(int d);
/* Set maximum supported depth */
void setMaxDepth(int d)
{ actMaxDepth = (d>maxDepth) ? maxDepth-1 : d; }
private:
Move move[maxDepth][maxDepth];
int actMaxDepth;
};
#endif /* _MOVE_H_ */
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include "network.h"
// set to 1 to get debug messages
int verbose = 0;
// NetworkLoop
NetworkLoop::NetworkLoop()
{
domainList = 0;
timerList = 0;
max_readfd = -1;
FD_ZERO(&readfds);
}
bool NetworkLoop::install(NetworkDomain* d)
{
if (d->isListening()) return false;
int fd = d->startListening(this);
if (fd>=0) {
FD_SET(fd, &readfds);
if (fd>max_readfd) max_readfd=fd;
}
if (verbose>1)
printf("NetworkLoop::install: Callbacks for NetworkDomain %d\n",
d->ID());
d->next = domainList;
domainList = d;
return true;
}
bool NetworkLoop::install(NetworkTimer* t)
{
t->reset();
t->next = timerList;
timerList = t;
if (verbose>1)
printf("NetworkLoop::install: Timer with %d msecs\n", t->msecs());
return true;
}
void NetworkLoop::remove(NetworkDomain* domain)
{
NetworkDomain *d, *prev=0;
for(d=domainList; d!=0; prev=d, d=d->next)
if (d == domain) break;
if (d==0) return;
int fd = d->listeningFD();
if (fd>=0) {
FD_CLR(fd, &readfds);
while(max_readfd>=0) {
if (FD_ISSET(max_readfd, &readfds)) break;
max_readfd--;
}
}
d->close();
if (prev) prev->next = d->next;
else domainList = d->next;
d->next = 0;
}
/* subtrace tv2 from tv1 */
void subTimeval(struct timeval* tv1, struct timeval* tv2)
{
tv1->tv_sec -= tv2->tv_sec;
if (tv1->tv_usec < tv2->tv_usec) {
tv1->tv_sec --;
tv1->tv_usec += 1000000 - tv2->tv_usec;
}
else
tv1->tv_usec -= tv2->tv_usec;
}
int NetworkLoop::run()
{
struct timeval tv, *ptv, tv2;
NetworkTimer *t, *tprev, *tnext;
tv2.tv_sec = 0;
tv2.tv_usec = 0;
exit_loop = false;
if (verbose>1)
printf("NetworkLoop::run: Waiting for events\n");
while(!exit_loop) {
if (timerList==0) ptv = 0;
else {
ptv = &tv;
timerList->set(&tv);
t = timerList->next;
for(;t!=0;t=t->next)
t->minLeft(&tv);
tv2 = tv;
}
fd_set rfds = readfds;
select(max_readfd+1, &rfds, NULL, NULL, ptv);
if (verbose>1) printf("NetworkLoop::run: Got a event...\n");
NetworkDomain* d = domainList;
for(;d!=0;d = d->next)
d->check(&rfds);
if (ptv) {
// Warning: Linux specific
subTimeval(&tv2, ptv);
tprev = 0;
t = timerList;
for(;t!=0;tprev=t,t=tnext) {
tnext = t->next;
if (t->subLeft(&tv2)) {
// remove timer, it could be added again in timeout()
if (tprev) tprev->next = tnext;
else timerList = tnext;
if (verbose>1)
printf("NetworkLoop::run: Timeout\n");
t->timeout(this);
}
}
}
}
return exit_value;
}
void NetworkLoop::exit(int v)
{
exit_loop = true;
exit_value = v;
}
bool NetworkLoop::pending()
{
fd_set rfds = readfds;
select(max_readfd+1, &rfds, NULL, NULL, NULL);
for(int i = 0;i<=max_readfd;i++)
if (FD_ISSET(i, &rfds)) return true;
return false;
}
void NetworkLoop::processPending()
{
fd_set rfds = readfds;
select(max_readfd+1, &rfds, NULL, NULL, NULL);
NetworkDomain* d = domainList;
for(;d!=0;d = d->next)
d->check(&rfds);
}
/// NetworkTimer
NetworkTimer::NetworkTimer(int msecs)
{
_msecs = msecs;
next = 0;
}
void NetworkTimer::timeout(NetworkLoop*)
{
printf("Timeout after %d.%03d secs!\n", _msecs/1000, _msecs%1000);
}
void NetworkTimer::reset()
{
_left.tv_sec = _msecs/1000;
_left.tv_usec = (_msecs%1000)*1000;
}
void NetworkTimer::set(struct timeval* tv)
{
tv->tv_sec = _left.tv_sec;
tv->tv_usec = _left.tv_usec;
}
void NetworkTimer::minLeft(struct timeval* tv)
{
if (_left.tv_sec < tv->tv_sec) {
tv->tv_sec = _left.tv_sec;
tv->tv_usec = _left.tv_usec;
return;
}
if (_left.tv_sec > tv->tv_sec) return;
if (_left.tv_usec > tv->tv_usec) return;
tv->tv_usec = _left.tv_usec;
}
bool NetworkTimer::subLeft(struct timeval* tv)
{
if (_left.tv_sec < tv->tv_sec) return true;
if (_left.tv_sec == tv->tv_sec)
if (_left.tv_usec <= tv->tv_usec) return true;
subTimeval(&_left, tv);
return false;
}
/// Connection
Connection::Connection(NetworkDomain* d, Connection* n,
const char* h, int p, struct sockaddr_in s,bool r)
{
setHost(h);
port = p;
sin = s;
reachable = r;
domain = d;
next = n;
}
Connection::~Connection()
{
if (reachable) {
char tmp[50];
int len = sprintf(tmp, "unreg %d", domain->listeningPort());
sendString(tmp, len);
}
}
void Connection::setHost(const char* h)
{
if (h==0)
host[0]=0;
else {
int l = strlen(h);
if (l>99) l=99;
strncpy(host, h, l);
host[l] = 0;
}
}
char* Connection::addr()
{
static char tmp[256];
sprintf(tmp, "%s:%d", host[0] ? host:inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port));
return tmp;
}
bool Connection::sendString(const char* str, int len)
{
if (!reachable) return false;
int s = ::socket (PF_INET, SOCK_STREAM, 0);
if (s<0) {
printf("Connection::sendString: Error in socket()\n");
return false;
}
if (::connect (s, (struct sockaddr *)&sin, sizeof (sin)) <0) {
if (verbose)
printf("Connection::sendString: Error in connect to %s\n", addr());
reachable = false;
return false;
}
write(s, str, len);
::close(s);
if (verbose>1)
printf("Connection::sendString: Sent to %s: '%s'\n", addr(), str);
return true;
}
bool Connection::start()
{
if (verbose)
printf("Connection::start: %s\n", addr());
char tmp[50];
int len = sprintf(tmp, "reg %d", domain->listeningPort());
reachable = true;
if (!sendString(tmp, len)) {
reachable = false;
return false;
}
domain->newConnection(this);
return true;
}
/// NetworkDomain
NetworkDomain::NetworkDomain(int id)
{
myID = id;
myPort = -1;
fd = -1;
loop = 0;
connectionList = 0;
}
NetworkDomain::~NetworkDomain()
{
if (loop)
loop->remove(this);
}
int NetworkDomain::startListening(NetworkLoop* l)
{
struct sockaddr_in name;
int i,j;
if (loop) return -1;
loop = l;
fd = ::socket (PF_INET, SOCK_STREAM, 0);
if (fd<0) return fd;
for(i = 0; i<5;i++) {
myPort = myID + i;
name.sin_family = AF_INET;
name.sin_port = htons (myPort);
name.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind (fd, (struct sockaddr *) &name, sizeof (name)) >= 0)
break;
if (verbose)
printf("NetworkDomain::startListening: Port %d in use\n", myPort);
}
mySin = name;
if (verbose)
printf("NetworkDomain::startListening: Using Port %d\n", myPort);
if (i==5) {
printf("NetworkDomain::startListening: Error starting domain %d\n",
myID);
::close(fd);
fd = -1;
myPort = -1;
return fd;
}
// connect to all instances of this domain on localhost
for(j = 0; j<5;j++) {
if (j == i) continue;
prepareConnection("localhost", myID+j);
}
if (::listen(fd,5)<0) {
printf("NetworkDomain::startListening: Error in listen\n");
::close(fd);
fd = -1;
return fd;
}
Connection *c;
for(c=connectionList; c!=0; c=c->next)
if (!c->reachable)
c->start();
return fd;
}
void NetworkDomain::close()
{
if (fd<0) return;
::close(fd);
Connection *l, *lnext;
for(l=connectionList; l!=0; l=lnext) {
lnext = l->next;
delete l;
}
loop = 0;
}
void NetworkDomain::check(fd_set* set)
{
if (FD_ISSET(fd, set)) gotConnection();
}
Connection* NetworkDomain::getNewConnection(const char* h,
struct sockaddr_in sin)
{
Connection* c;
for(c=connectionList; c!=0; c=c->next)
if (c->sin.sin_addr.s_addr == sin.sin_addr.s_addr &&
c->sin.sin_port == sin.sin_port) break;
if (c) {
if (h) c->setHost(h);
c->reachable = false;
}
else {
c = new Connection(this, connectionList,
h, ntohs(sin.sin_port),
sin, false);
connectionList = c;
}
return c;
}
void NetworkDomain::gotConnection()
{
static char tmp[1024];
int len=0;
struct sockaddr_in sin;
socklen_t sz = sizeof (sin);
if (verbose>1)
printf("NetworkDomain::GotConnection:\n");
int s = accept(fd,(struct sockaddr *)&sin, &sz);
if (s<0) {
printf(" Error in accept\n");
return;
}
while(read(s, tmp+len, 1)==1) len++;
::close(s);
tmp[len]=0; len++;
if (verbose>1)
printf(" Got from %s:%d : '%s'\n",
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), tmp);
if (strncmp(tmp,"reg ",4)==0) {
int port = atoi(tmp+4);
sin.sin_port = htons( port );
Connection *c = getNewConnection(0, sin);
c->reachable = true;
if (verbose)
printf("Reg of %s\n", c->addr());
newConnection(c);
return;
}
if (strncmp(tmp,"unreg ",6)==0) {
int port = atoi(tmp+6);
sin.sin_port = htons( port );
Connection *c, *cprev=0;
for(c=connectionList ; c!=0; cprev=c, c=c->next)
if (c->sin.sin_addr.s_addr == sin.sin_addr.s_addr &&
c->sin.sin_port == sin.sin_port) break;
if (c==0) {
printf("Error: UnReg of %s:%d. Not Found\n",
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
return;
}
if (cprev) cprev->next = c->next;
else connectionList = c->next;
if (verbose)
printf("UnReg of %s:%d\n",
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
return;
}
received(tmp);
}
int NetworkDomain::count()
{
int cc = 0;
for(Connection* c=connectionList; c!=0; c=c->next)
if (c->reachable) cc++;
return cc;
}
void NetworkDomain::received(char* str)
{
printf("NetworkDomain::received: '%s' in domain %d\n",
str, ID());
}
void NetworkDomain::newConnection(Connection* c)
{
if (verbose)
printf("NetworkDomain::newConnection: %s, now %d active connections\n",
c->addr(), count());
}
void NetworkDomain::addConnection(const char* host, int port)
{
Connection* c = prepareConnection(host,port);
if (c) c->start();
}
Connection* NetworkDomain::prepareConnection(const char* host, int port)
{
struct hostent *hostinfo;
struct sockaddr_in name;
memset(&name, 0, sizeof(struct sockaddr_in));
name.sin_family = AF_INET;
name.sin_port = htons (port);
hostinfo = gethostbyname (host);
if (hostinfo == NULL) {
printf ("NetworkDomain::prepareConnection: Error: Unknown host %s.\n",
host);
return 0;
}
name.sin_addr = *(struct in_addr *) hostinfo->h_addr;
return getNewConnection(host, name);
}
void NetworkDomain::broadcast(const char* str)
{
int len = strlen(str);
for(Connection* c=connectionList; c!=0; c=c->next)
c->sendString(str, len);
}
/*
* Simple Network Communication via event-driven loop
*
* (C) 2005, Josef Weidendorfer
*
* Install a communication domain which is a listening socket
* on a port and a set of remote connection to this port.
* You can register callbacks for incoming ASCII data on
* communcation domains and broadcast your own data into a domain.
*/
#ifndef NETWORK_H
#define NETWORK_H
#include <sys/types.h>
#include <netinet/in.h>
class NetworkDomain;
class NetworkTimer;
/**
* Event loop for network communication
*/
class NetworkLoop
{
public:
NetworkLoop();
/**
* Install a listening socket on the port given by the NetworkDomain.
* Incoming connections are accepted, and incoming
* data will lead to callbacks specified in the NetworkDomain.
* Returns true if successfull.
*/
bool install(NetworkDomain*);
/**
* Install a oneshot timer object. Install the timer again in
* timeout() for regular calls.
*/
bool install(NetworkTimer*);
/**
* Remove a NetworkDomain. Existing connections will be closed.
*/
void remove(NetworkDomain*);
/**
* Blocks in a select() on network connections and
* calls registered callbacks on incoming data.
* Call exit() to leave the event loop with given exit value.
*/
int run();
/**
* While running inside of a event loop via run(),
* call this function the trigger quitting the loop, i.e.
* returning from run().
*/
void exit(int value = 1);
/**
* Are incoming data pending?
*/
bool pending();
/**
* Process pending data
*/
void processPending();
private:
NetworkDomain* domainList;
NetworkTimer* timerList;
bool exit_loop;
int exit_value;
/* Set of file descriptors used in select.
* This includes listening and data sockets
*/
fd_set readfds;
int max_readfd;
};
/**
* A timer to be used with NetworkLoop.
*
* Install an instance into the loop to get timeout() called
* after <secs> seconds.
*/
class NetworkTimer
{
public:
NetworkTimer(int msecs);
virtual ~NetworkTimer() {}
int msecs() { return _msecs; }
virtual void timeout(NetworkLoop*);
/**
* Internal.
* Helpers for NetworkLoop
*/
void reset();
void set(struct timeval*);
void minLeft(struct timeval*);
bool subLeft(struct timeval*);
NetworkTimer* next;
private:
int _msecs;
struct timeval _left;
};
/**
* An active connection in a communication domain
*/
class Connection {
public:
Connection(NetworkDomain*, Connection*,
const char*, int,
struct sockaddr_in, bool);
~Connection();
void setHost(const char* h);
/**
* Send a string to this connection.
*/
bool sendString(const char* str, int len);
/* Get string for remote end */
char* addr();
/**
* Internal.
* Called from NetworkDomain to send registration string
*/
bool start();
char host[100];
int port;
struct sockaddr_in sin;
bool reachable;
NetworkDomain* domain;
Connection* next;
};
/**
* The Network domainclass can be subclassed to send and to
* receive multicasts from other Network instances in
* other processes/machines.
*/
class NetworkDomain
{
public:
enum { defaultPort = 23412 };
/* install listening TCP socket on port */
NetworkDomain(int port = defaultPort);
virtual ~NetworkDomain();
bool isListening() { return (fd>=0); }
/**
* Returns the file descriptor for the listening socket
*/
int startListening(NetworkLoop*);
/**
* Close all connections and listening socket
*/
void close();
int ID() { return myID; }
int listeningPort() { return myPort; }
int listeningFD() { return fd; }
void addConnection(const char* host, int port);
void broadcast(const char* str);
/* return number of connections */
int count();
/* For list of domains used in a NetworkLoop.
* Can be done this way as a NetworkDomain can only be used
* in one NetworkLoop at a time
*/
NetworkDomain* next;
/**
* Internal use.
* NetworkLoop asks to check for pending connections and data
*/
void check(fd_set*);
/**
* Internal use.
* Overwrite this to react on new connections
*/
virtual void newConnection(Connection*);
protected:
/* overwrite this in your subclass to receive
* strings broadcasted */
virtual void received(char* str);
Connection* prepareConnection(const char* host, int port);
private:
void gotConnection();
/* factory for connections to not get multiply connections to one target */
Connection* getNewConnection(const char* h, struct sockaddr_in sin);
NetworkLoop* loop;
Connection* connectionList;
struct sockaddr_in mySin;
int fd, myID, myPort;
};
#endif
/**
* Computer player
*
* (1) Connects to a game communication channel,
* (2) Waits for a game position requiring to draw a move,
* (3) Does a best move search, and broadcasts the resulting position,
* Jump to (2)
*
* (C) 2005, Josef Weidendorfer
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <mpi.h>
#include "board.h"
#include "search.h"
#include "eval.h"
#include "network.h"
#define pretty_print(name, val) printf("%s = %d: %s: %s: %d\n", name, val, __FILE__,__FUNCTION__,__LINE__);
int thread_rank;
int num_threads;
FILE *file;
/* Global, static vars */
NetworkLoop l;
Board b;
Evaluator ev;
/* Which color to play? */
int myColor = Board::color1;
/* Which search strategy to use? */
int strategyNo = 0;
/* Max search depth */
int maxDepth = 0;
/* Maximal number of moves before terminating (negative for infinity) */
int maxMoves = -1;
/* to set verbosity of NetworkLoop implementation */
extern int verbose;
/* remote channel */
char* host = 0; /* not used on default */
int rport = 23412;
/* local channel */
int lport = 13133;
/* change evaluation after move? */
bool changeEval = true;
char global_tmp[500];
/**
* MyDomain
*
* Class for communication handling for player:
* - start search for best move if a position is received
* in which this player is about to draw
*/
class MyDomain: public NetworkDomain
{
public:
MyDomain(int p) : NetworkDomain(p) {}
void sendBoard();
// protected:
void received(char* str);
};
void MyDomain::sendBoard()
{
static char tmp[500];
sprintf(tmp, "pos %s\n", b.getState());
if (verbose) printf(tmp+4);
broadcast(tmp);
}
void MyDomain::received(char* str)
{
if (strncmp(str, "quit", 4)==0) {
l.exit();
return;
}
if (strncmp(str, "pos ", 4)!=0) return;
b.setState(str+4);
if (verbose) {
printf("\n\n==========================================\n");
printf(str+4);
}
int state = b.validState();
if ((state != Board::valid1) &&
(state != Board::valid2)) {
printf("%s\n", Board::stateDescription(state));
switch(state) {
case Board::timeout1:
case Board::timeout2:
case Board::win1:
case Board::win2:
l.exit();
default:
break;
}
return;
}
if (b.actColor() & myColor) {
struct timeval t1, t2;
gettimeofday(&t1,0);
Move m = b.bestMove();
gettimeofday(&t2,0);
int msecsPassed =
(1000* t2.tv_sec + t2.tv_usec / 1000) -
(1000* t1.tv_sec + t1.tv_usec / 1000);
printf("%s ", (myColor == Board::color1) ? "O":"X");
if (m.type == Move::none) {
printf(" can not draw any move ?! Sorry.\n");
return;
}
printf("draws '%s' (after %d.%03d secs)...\n",
m.name(), msecsPassed/1000, msecsPassed%1000);
b.playMove(m, msecsPassed);
sendBoard();
if (changeEval)
ev.changeEvaluation();
/* stop player at win position */
int state = b.validState();
if ((state != Board::valid1) &&
(state != Board::valid2)) {
printf("%s\n", Board::stateDescription(state));
switch(state) {
case Board::timeout1:
case Board::timeout2:
case Board::win1:
case Board::win2:
l.exit();
default:
break;
}
}
maxMoves--;
if (maxMoves == 0) {
printf("Terminating because given number of moves drawn.\n");
broadcast("quit\n");
l.exit();
}
}
}
/*
* Main program
*/
void printHelp(char* prg, bool printHeader)
{
if (printHeader)
printf("Computer player V 0.1 - (C) 2005 Josef Weidendorfer\n"
"Search for a move on receiving a position in which we are expected to draw.\n\n");
printf("Usage: %s [options] [X|O] [<strength>]\n\n"
" X Play side X\n"
" O Play side O (default)\n"
" <strength> Playing strength, depending on strategy\n"
" A time limit can reduce this\n\n" ,
prg);
printf(" Options:\n"
" -h / --help Print this help text\n"
" -v / -vv Be verbose / more verbose\n"
" -s <strategy> Number of strategy to use for computer (see below)\n"
" -n Do not change evaluation function after own moves\n"
" -<integer> Maximal number of moves before terminating\n"
" -p [host:][port] Connection to broadcast channel\n"
" (default: 23412)\n\n");
printf(" Available search strategies for option '-s':\n");
char** strs = SearchStrategy::strategies();
for(int i = 0; strs[i]; i++)
printf(" %2d : Strategy '%s'%s\n", i, strs[i],
(i==strategyNo) ? " (default)":"");
printf("\n");
exit(1);
}
void parseArgs(int argc, char* argv[])
{
int arg=0;
while(arg+1<argc) {
arg++;
if (strcmp(argv[arg],"-h")==0 ||
strcmp(argv[arg],"--help")==0) printHelp(argv[0], true);
if (strncmp(argv[arg],"-v",2)==0) {
verbose = 1;
while(argv[arg][verbose+1] == 'v') verbose++;
continue;
}
if (strcmp(argv[arg],"-n")==0) {
changeEval = false;
continue;
}
if ((strcmp(argv[arg],"-s")==0) && (arg+1<argc)) {
arg++;
if (argv[arg][0]>='0' && argv[arg][0]<='9')
strategyNo = argv[arg][0] - '0';
continue;
}
if ((argv[arg][0] == '-') &&
(argv[arg][1] >= '0') &&
(argv[arg][1] <= '9')) {
int pos = 2;
maxMoves = argv[arg][1] - '0';
while((argv[arg][pos] >= '0') &&
(argv[arg][pos] <= '9')) {
maxMoves = maxMoves * 10 + argv[arg][pos] - '0';
pos++;
}
continue;
}
if ((strcmp(argv[arg],"-p")==0) && (arg+1<argc)) {
arg++;
if (argv[arg][0]>'0' && argv[arg][0]<='9') {
lport = atoi(argv[arg]);
continue;
}
char* c = strrchr(argv[arg],':');
int p = 0;
if (c != 0) {
*c = 0;
p = atoi(c+1);
}
host = argv[arg];
if (p) rport = p;
continue;
}
if ((strcmp(argv[arg],"-f")==0) && (arg+1<argc)) {
arg++;
file = fopen(argv[arg], "r");
//arg++;
continue;
}
if (argv[arg][0] == 'X') {
myColor = Board::color2;
continue;
}
if (argv[arg][0] == 'O') {
myColor = Board::color1;
continue;
}
int strength = atoi(argv[arg]);
if (strength == 0) {
printf("ERROR - Unknown option %s\n", argv[arg]);
printHelp(argv[0], false);
}
maxDepth = strength;
}
}
extern int avg_kleavesPerSec;
extern int _msecs;
Move m;
int main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_threads);
MPI_Comm_rank(MPI_COMM_WORLD, &thread_rank);
parseArgs(argc, argv);
if (file){
int len = 0, c;
while( len<499 && (c=fgetc(file)) != EOF)
global_tmp[len++] = (char) c;
global_tmp[len++]=0;
//printf("Gaurav\n");
//printf("%s",global_tmp);
//printf("Gaurav\n");
}
SearchStrategy* ss = SearchStrategy::create(strategyNo);
if (verbose)
printf("Using strategy '%s' ...\n", ss->name());
ss->setMaxDepth(maxDepth);
b.setSearchStrategy( ss );
ss->setEvaluator(&ev);
ss->registerCallbacks(new SearchCallbacks(verbose));
if(thread_rank == 0) {
MyDomain d(lport);
d.received(global_tmp);
// Send a signal to the slaves, that they should quit
Slave_Input slave_input;
slave_input.depth = -1;
int slave_id;
for (slave_id = 0; slave_id < num_threads-1; slave_id++)
MPI_Send(&slave_input, sizeof(Slave_Input), MPI_BYTE, slave_id + 1, 10, MPI_COMM_WORLD);
//printf("Average leaves visited per sec = %d k/s\n", avg_kleavesPerSec);
}
else
{
while (1)
{
MPI_Status mpi_st;
Slave_Input slave_input;
Slave_Output slave_output;
MPI_Recv (&slave_input, sizeof(Slave_Input), MPI_BYTE, 0, 10, MPI_COMM_WORLD, &mpi_st);
// depth= -1 is a signal for the slave to quit
if (slave_input.depth == -1)
break;
ss->_board = &b;
ss->_board->setState(slave_input.boardstate);
ss->_board->playMove(slave_input.move);
((ABIDStrategy*)ss)->_currentMaxDepth = slave_input.currentMaxDepth;
ss->_sc->_leavesVisited = 0;
ss->_sc->_nodesVisited = 0;
/* check for a win position first */
if (!ss->_board->isValid())
{
slave_output.eval = (14999-(slave_input.depth-1));
}
else
{
if ((slave_input.depth == slave_input.currentMaxDepth) && (slave_input.move.type > Move::maxPushType ))
slave_output.eval = ss->evaluate();
else
slave_output.eval = -((ABIDStrategy*)ss)->alphabeta(slave_input.depth, slave_input.alpha, slave_input.beta);
}
((ABIDStrategy*)ss)->_pv.update(slave_input.depth-1, slave_input.move);
slave_output.pv = ((ABIDStrategy*)ss)->_pv;
slave_output.num_leaves = ss->_sc->_leavesVisited;
slave_output.num_nodes = ss->_sc->_nodesVisited;
MPI_Send(&slave_output, sizeof(Slave_Output), MPI_BYTE, 0, 10, MPI_COMM_WORLD);
}
}
/*
int *avg_list;
avg_list = (int*)malloc(sizeof(int)*num_threads);
MPI_Gather (&avg_kleavesPerSec, 1, MPI_INT,
avg_list, 1, MPI_INT, 0, MPI_COMM_WORLD);
if(thread_rank == 0)
{
int average;
for(int i=0;i<num_threads;i++) {
average += avg_list[i];
}
printf("\n\n\n%d, %d, %d, %f, %s\n", num_threads, maxDepth, average, _msecs/1000.0, ss->_bestMove.name());
}*/
MPI_Finalize();
}
pos #69 O: 14, X: 10
-----------
/ . . . . . \
/ . O . . . . \
/ . . O . . . . \
/ . . X . O . . . \
| . X X O O O O . . |
\ . X . O O O . . /
\ . O O O O . . /
\ . X X X X . /
\ . . X . X /
-----------
X about to move...
=========================================================
Start from this position with
./start position-endgame
Results for "./player <Strength> X"
(Sequential search, Pentium M, 1.6 GHz)
Strength | Move | Evaluated | Time [s] | Rate
| | | -O3 | [Evals/s]
1 I9/RightUp 384
2 I7/LeftUp/Psh 1 796 .042 43 k
3 I7/LeftUp/Psh 17 823 .169 105 k
4 I7/LeftUp/Psh 23 266 .255 91 k
5 I7/LeftUp/Psh 1 520 313 5.715 266 k
6 I7/LeftUp/Psh 11 196 668 39.575 283 k
pos #29 O: 14, X: 14
-----------
/ . . . . . \
/ . O O O O . \
/ . O O . O . . \
/ . . O O O . . . \
| . . O O O . . . . |
\ . X O X X X . . /
\ . X X X X X . /
\ X X X X X . /
\ . . . . . /
-----------
X about to move...
=========================================================
Start from this position with
./start position-midgame1
Results for "./player <Strength> X"
(Sequential search, Pentium M, 1.6 GHz)
Strength | Move | Evaluated | Time [s] | Rate
| | | -O3 | [Evals/s]
1 F3/LeftDown 71
2 F3-G4/Left 5 199 .064 81 k
3 F3-G4/Left 120 718 .649 186 k
4 G4/LeftUp 2 485 542 11.067 225 k
5 G4/RightDown 15 018 100 70.446 213 k
pos #120 O: 14, X: 12
-----------
/ . . . . . \
/ O O O O O . \
/ . O O X O . . \
/ . O X O O . . . \
| . O O X X X . . . |
\ . . O X X X . . /
\ . . X . X . . /
\ . X . X . . /
\ . . . . . /
-----------
O about to move...
=========================================================
Start from this position with
./start position-midgame2
Results for "./player <Strength> O"
(Sequential search, Pentium M, 1.6 GHz)
Strength | Move | Evaluated | Time [s] | Rate
| | | -O3 | [Evals/s]
1 E3-F4/LeftDown 257
2 B1/RightUp 4 358 .062 70 k
3 C2-E2/Left 97 908 .505 194 k
4 B1/LeftDown 1 519 234 5.007 303 k
5 C2-D2/Left 4 411 737 15.265 289 k
pos #1 O: 14, X: 14
-----------
/ O O O O O \
/ O O O O O O \
/ . . O O O . . \
/ . . . . . . . . \
| . . . . . . . . . |
\ . . . . . . . . /
\ . . X X X . . /
\ X X X X X X /
\ X X X X X /
-----------
X about to move...
=========================================================
/**
* Referee
*
* Send a start position into 2 game communication channels,
* observe positions sent in one channel, and if valid, broadcast
* them into other channel.
* For a time limited game, times are updated by referee itself.
*
* (C) 2005, Josef Weidendorfer
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include "board.h"
#include "network.h"
/* Global, static vars */
static NetworkLoop l;
static Board b;
/* Time of last draw */
static struct timeval t1;
class MyDomain;
static MyDomain *d1 = 0, *d2 = 0;
/*
* Do other members in the channels exist at all?
* Only start time if there are players.
*
* Note: We can not distinguish between observers and players,
* so game always start when another member is seen.
*/
static bool d1MemberExists = false;
static bool d2MemberExists = false;
/* time limit in seconds (0: no time limit) */
static int secsToPlay = 0;
static int msecsToPlay[3] = {0,0,0};
/* to set verbosity of NetworkLoop implementation */
extern int verbose;
#define DEFAULT_DOMAIN_PORT 13375
#define DEFAULT_DOMAIN_DIFF 50
/* remote channel */
static char* host[2] = {0,0}; /* not used per default */
static int rport[2] = {DEFAULT_DOMAIN_PORT, DEFAULT_DOMAIN_PORT + DEFAULT_DOMAIN_DIFF};
/* local channel */
static int lport[2] = {DEFAULT_DOMAIN_PORT, DEFAULT_DOMAIN_PORT + DEFAULT_DOMAIN_DIFF};
/* Where to read position to broadcast from? (0: start position) */
static FILE* file = 0;
class MyDomain: public NetworkDomain
{
public:
MyDomain(int p) : NetworkDomain(p) {}
void sendBoard();
protected:
void received(char* str);
void newConnection(Connection*);
};
void MyDomain::sendBoard()
{
static char tmp[500];
sprintf(tmp, "pos %s\n", b.getState());
if (verbose) {
printf(tmp+4);
int state = b.validState();
printf("%s\n", Board::stateDescription(state));
}
broadcast(tmp);
}
void MyDomain::received(char* str)
{
if (strncmp(str, "quit", 4)==0) {
l.exit();
return;
}
if (strncmp(str, "pos ", 4)!=0) return;
if (b.validState() != Board::empty) {
Board newBoard;
newBoard.setState(str+4);
Move m = b.moveToReach(&newBoard, false);
if (m.type == Move::none) {
printf("WARNING: Got a board which is not reachable via a valid move !?\n");
return;
}
else {
struct timeval t2;
gettimeofday(&t2,0);
int msecsPassed =
(1000* t2.tv_sec + t2.tv_usec / 1000) -
(1000* t1.tv_sec + t1.tv_usec / 1000);
t1 = t2;
int* pMSecs;
if (b.actColor() == Board::color1) {
pMSecs = &(msecsToPlay[Board::color1]);
printf("O");
}
else {
pMSecs = &(msecsToPlay[Board::color2]);
printf("X");
}
printf(" draws '%s' (after %d.%03d secs)...\n",
m.name(), msecsPassed/1000, msecsPassed%1000);
if (*pMSecs > msecsPassed)
*pMSecs -= msecsPassed;
else
*pMSecs = 0;
}
}
b.setState(str+4);
/* force our objective view regarding time */
b.setMSecsToPlay(Board::color1, msecsToPlay[Board::color1] );
b.setMSecsToPlay(Board::color2, msecsToPlay[Board::color2] );
printf(b.getState());
int state = b.validState();
printf("%s\n", Board::stateDescription(state));
switch(state) {
case Board::timeout1:
case Board::timeout2:
case Board::win1:
case Board::win2:
l.exit();
default:
break;
}
/* send to other domain */
if (d1 == this) if (d2) d2->sendBoard();
if (d2 == this) if (d1) d1->sendBoard();
}
void MyDomain::newConnection(Connection* c)
{
NetworkDomain::newConnection(c);
static char tmp[500];
int len = sprintf(tmp, "pos %s\n", b.getState());
c->sendString(tmp, len);
/* adjust time if this is first connection for the channel */
if (!d1MemberExists && (this == d1)) {
d1MemberExists = true;
gettimeofday(&t1,0);
}
if (!d2MemberExists && (this == d2)) {
d2MemberExists = true;
gettimeofday(&t1,0);
}
}
static void printHelp(char* prg, bool printHeader)
{
if (printHeader)
printf("Referee V 0.1 - (C) 2005 Josef Weidendorfer\n"
"Broadcast a game position into 2 domains, observe moves played in one domain,\n"
"and if valid, broadcast to other domain. Stops playing times itself.\n\n");
printf("Usage: %s [options] [<file>|-]\n\n"
" <file> File containing game position (default: start position)\n"
" - Position is read from standard input\n\n",
prg);
printf(" Options:\n"
" -h / --help Print this help text\n"
" -v / -vv Be verbose / more verbose\n"
" -t <timeToPlay> Start in tournament modus (limited time)\n"
" -p [host:][port] Connection to first (second) broadcast channel\n"
" (default: %d / %d)\n\n",
DEFAULT_DOMAIN_PORT, DEFAULT_DOMAIN_PORT + DEFAULT_DOMAIN_DIFF);
exit(1);
}
static void parseArgs(int argc, char* argv[])
{
int domainsSet = 0;
int arg=0;
while(arg+1<argc) {
arg++;
if (argv[arg][0] == '-') {
if (strcmp(argv[arg],"-h")==0 ||
strcmp(argv[arg],"--help")==0) printHelp(argv[0], true);
if (strcmp(argv[arg],"-v")==0) {
verbose = 1;
continue;
}
if (strcmp(argv[arg],"-vv")==0) {
verbose = 2;
continue;
}
if ((strcmp(argv[arg],"-t")==0) && (arg+1<argc)) {
arg++;
secsToPlay = atoi(argv[arg]);
if (secsToPlay == 0) {
printf("%s: WARNING - Ignoring tournament; %d secs to play\n",
argv[0], secsToPlay);
}
continue;
}
if ((strcmp(argv[arg],"-p")==0) && (arg+1<argc)) {
arg++;
if (domainsSet>1) {
printf("%s: WARNING - Domain specification %s ignored.\n",
argv[0], argv[arg]);
continue;
}
if (argv[arg][0]>'0' && argv[arg][0]<='9') {
lport[domainsSet] = atoi(argv[arg]);
domainsSet++;
continue;
}
char* c = strrchr(argv[arg],':');
int p = 0;
if (c != 0) {
*c = 0;
p = atoi(c+1);
}
host[domainsSet] = argv[arg];
if (p) rport[domainsSet] = p;
domainsSet++;
continue;
}
if (strcmp(argv[arg],"-")==0) {
file = stdin;
continue;
}
printf("%s: ERROR - Unknown option %s\n", argv[0], argv[arg]);
printHelp(argv[0], false);
}
file = fopen(argv[arg], "r");
if (!file) {
printf("%s: ERROR - Can not open '%s' for reading start position\n",
argv[0], argv[arg]);
printHelp(argv[0], false);
}
break;
}
if (lport[0] == lport[1]) {
lport[1] = lport[0] + DEFAULT_DOMAIN_DIFF;
printf("Local port for domain 2 set to %d\n", lport[1]);
}
}
int main(int argc, char* argv[])
{
parseArgs(argc, argv);
b.setVerbose(verbose);
if (file) {
char tmp[500];
int len = 0, c;
while( len<499 && (c=fgetc(file)) != EOF)
tmp[len++] = (char) c;
tmp[len++]=0;
if (!b.setState(tmp)) {
printf("%s: WARNING - Can not parse given position; using start position\n", argv[0]);
b.begin(Board::color1);
}
}
else
b.begin(Board::color1);
if (secsToPlay >= 0) {
msecsToPlay[Board::color1] = 1000 * secsToPlay;
msecsToPlay[Board::color2] = 1000 * secsToPlay;
}
else {
msecsToPlay[Board::color1] = b.msecsToPlay(Board::color1);
msecsToPlay[Board::color2] = b.msecsToPlay(Board::color2);
}
b.setMSecsToPlay(Board::color1, msecsToPlay[Board::color1] );
b.setMSecsToPlay(Board::color2, msecsToPlay[Board::color2] );
/*
* Register domains at NetworkLoop. Existing members will
* get sent the board via MyDomain::newConnection
*/
d1 = new MyDomain(lport[0]);
if (host[0]) d1->addConnection(host[0], rport[0]);
d2 = new MyDomain(lport[1]);
if (host[1]) d2->addConnection(host[1], rport[1]);
l.install(d1);
l.install(d2);
d1MemberExists = d1->count() >0;
d2MemberExists = d2->count() >0;
gettimeofday(&t1,0);
return l.run();
}
/**
* A real world, sequential strategy:
* Alpha/Beta with Iterative Deepening (ABID)
*
* (c) 2005, Josef Weidendorfer
*/
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <string.h>
#include "search.h"
#include "board.h"
extern int thread_rank;
extern int num_threads;
/**
* Entry point for search
*
* Does iterative deepening and alpha/beta width handling, and
* calls alpha/beta search
*/
void ABIDStrategy::searchBestMove()
{
int alpha = -15000, beta = 15000;
int nalpha, nbeta, currentValue = 0;
_pv.clear(_maxDepth);
_currentBestMove.type = Move::none;
_currentMaxDepth=1;
/* iterative deepening loop */
do {
/* searches on same level with different alpha/beta windows */
while(1) {
nalpha = alpha, nbeta = beta;
_inPV = (_pv[0].type != Move::none);
if (_sc && _sc->verbose()) {
char tmp[100];
sprintf(tmp, "Alpha/Beta [%d;%d] with max depth %d", alpha, beta, _currentMaxDepth);
_sc->substart(tmp);
}
currentValue = pv_split(alpha, beta);
printf("Subsearch finished with currentValue = %d\n", currentValue);
/* stop searching if a win position is found */
if (currentValue > 14900 || currentValue < -14900)
_stopSearch = true;
/* Don't break out if we haven't found a move */
if (_currentBestMove.type == Move::none)
_stopSearch = false;
if (_stopSearch) break;
/* if result is outside of current alpha/beta window,
* the search has to be rerun with widened alpha/beta
*/
if (currentValue <= nalpha) {
alpha = -15000;
if (beta<15000) beta = currentValue+1;
continue;
}
if (currentValue >= nbeta) {
if (alpha > -15000) alpha = currentValue-1;
beta=15000;
continue;
}
break;
}
/* Window in both directions cause of deepening */
alpha = currentValue - 200, beta = currentValue + 200;
if (_stopSearch) break;
_currentMaxDepth++;
}
while(_currentMaxDepth <= _maxDepth);
_bestMove = _currentBestMove;
}
int ABIDStrategy::pv_split(int alpha0, int beta0)
{
int depth;
int value;
int currentValue = -15000;
int slave_id;
int num_slaves;
int pending_jobs;
Slave_Input slave_input;
Slave_Output *slave_output;
MPI_Request *rcv_rq;
MoveList list;
Move m, *movechain;
int *alpha, *beta;
rcv_rq = (MPI_Request *) malloc (num_threads * sizeof(MPI_Request));
slave_output = (Slave_Output *) malloc (num_threads * sizeof(Slave_Output));
movechain = (Move*) malloc ((_currentMaxDepth+1)* sizeof (Move));
alpha = (int*) malloc((_currentMaxDepth+2)*sizeof(int));
beta = (int*) malloc((_currentMaxDepth+2)*sizeof(int));
alpha[0] = alpha0;
beta[0] = beta0;
_currentBestMove.type = Move::none;
// Play moves from the pv until you reach the lowest level
// If pv-moves are not possible use random moves
// Store the sequence of moves in movechain
depth = 0;
while (depth < (_currentMaxDepth-1))
{
list.clear();
_board->generateMoves(list);
m = _pv[depth];
// check if pv-move is possible
if ((m.type != Move::none) && (!list.isElement(m, 0, false)))
m.type = Move::none;
// get random move if pv-move is not possible
if (m.type == Move::none)
list.getNext(m, Move::none);
_board->playMove(m);
movechain[depth] = m;
alpha[depth+1] = -beta[depth];
beta[depth+1] = -alpha[depth];
depth++;
}
// Start at the second lowest level and move back up the gametree
// Devide the work at each level
depth = _currentMaxDepth-1;
while (depth >= 0)
{
slave_id = 0;
list.clear();
_board->generateMoves(list);
// delete the move we already checked from the list
if (depth < _currentMaxDepth-1)
list.isElement(movechain[depth], 0, true);
strcpy(slave_input.boardstate,_board->getState());
slave_input.alpha = -beta[depth];
slave_input.beta = -alpha[depth];
slave_input.depth = depth+1;
slave_input.currentMaxDepth = _currentMaxDepth;
printf("Thread 0 testing %d moves at depth = %d\n",list.getLength(), depth);
while ( list.getNext(m, Move::none) )
{
slave_input.move = m;
MPI_Send(&slave_input, sizeof(Slave_Input), MPI_BYTE, slave_id+1, 10, MPI_COMM_WORLD);
MPI_Irecv(&slave_output[slave_id], sizeof(Slave_Output), MPI_BYTE, slave_id+1,
10, MPI_COMM_WORLD, &rcv_rq[slave_id]);
slave_id++;
if (slave_id >= (num_threads-1))
break;
}
num_slaves = slave_id;
pending_jobs = num_slaves;
while (pending_jobs > 0)
{
MPI_Waitany(num_slaves, rcv_rq, &slave_id, MPI_STATUS_IGNORE);
_sc->_leavesVisited += slave_output[slave_id].num_leaves;
_sc->_nodesVisited += slave_output[slave_id].num_nodes;
value = slave_output[slave_id].eval;
if (value > currentValue)
{
currentValue = value;
_pv = slave_output[slave_id].pv;
if (_sc)
_sc->foundBestMove(depth, _pv[depth], currentValue);
if (currentValue > alpha[depth])
{
alpha[depth] = currentValue;
slave_input.beta = -alpha[depth];
}
}
if (list.getNext(m, Move::none))
{
slave_input.move = m;
MPI_Send(&slave_input, sizeof(Slave_Input), MPI_BYTE, slave_id+1, 10, MPI_COMM_WORLD);
MPI_Irecv(&slave_output[slave_id], sizeof(Slave_Output), MPI_BYTE, slave_id+1,
10, MPI_COMM_WORLD, &rcv_rq[slave_id]);
}
else
pending_jobs--;
}
if (depth > 0)
{
_board->takeBack();
_pv.update(depth-1, movechain[depth-1]);
currentValue = -currentValue;
if (currentValue > alpha[depth -1])
alpha[depth-1] = currentValue;
}
if (depth == 0)
_currentBestMove = _pv[0];
if (_sc)
_sc->finishedNode(depth, _pv.chain(depth));
depth--;
}
free(slave_output);
free(rcv_rq);
free(movechain);
free(alpha);
free(beta);
return currentValue;
}
/*
* Alpha/Beta search
*
* - first, start with principal variation
* - depending on depth, we only do depth search for some move types
*/
int ABIDStrategy::alphabeta(int depth, int alpha, int beta)
{
int currentValue = -14999+depth, value;
Move m;
MoveList list;
bool depthPhase, doDepthSearch;
/* We make a depth search for the following move types... */
int maxType = (depth < _currentMaxDepth-1) ? Move::maxMoveType :
(depth < _currentMaxDepth) ? Move::maxPushType :
Move::maxOutType;
_board->generateMoves(list);
if (_sc && _sc->verbose()) {
char tmp[100];
sprintf(tmp, "Alpha/Beta [%d;%d], %d moves (%d depth)", alpha, beta,
list.count(Move::none), list.count(maxType));
_sc->startedNode(depth, tmp);
}
// don't use moves from the principal variation
m.type = Move::none;
// first, play all moves with depth search
depthPhase = true;
while (1) {
// get next move
if (m.type == Move::none) {
if (depthPhase)
depthPhase = list.getNext(m, maxType);
if (!depthPhase)
if (!list.getNext(m, Move::none)) break;
}
// we could start with a non-depth move from principal variation
doDepthSearch = depthPhase && (m.type <= maxType);
_board->playMove(m);
/* check for a win position first */
if (!_board->isValid()) {
/* Shorter path to win position is better */
value = 14999-depth;
}
else {
if (doDepthSearch) {
/* opponent searches for its maximum; but we want the
* minimum: so change sign (for alpha/beta window too!)
*/
value = -alphabeta(depth+1, -beta, -alpha);
}
else {
value = evaluate();
}
}
_board->takeBack();
/* best move so far? */
if (value > currentValue) {
currentValue = value;
_pv.update(depth, m);
/* alpha/beta cut off or win position ... */
if (currentValue>14900 || currentValue >= beta) {
if (_sc) _sc->finishedNode(depth, _pv.chain(depth));
return currentValue;
}
/* maximize alpha */
if (currentValue > alpha) alpha = currentValue;
}
if (_stopSearch) break; // depthPhase=false;
m.type = Move::none;
}
if (_sc) _sc->finishedNode(depth, _pv.chain(depth));
return currentValue;
}
// register ourselve
ABIDStrategy abidStrategy;
/*
* Very simple example strategy:
* Search all possible positions reachable via one move,
* and return the move leading to best position
*
* (c) 2006, Josef Weidendorfer
*/
#include <stdio.h>
#include "search.h"
#include "board.h"
#include "eval.h"
#define pretty_print(name, val) printf("%s = %d: %s: %s: %d\n", name, val, __FILE__,__FUNCTION__,__LINE__);
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
/**
* To create your own search strategy:
* - copy this file into another one,
* - change the class name one the name given in constructor,
* - adjust clone() to return an instance of your class
* - adjust last line of this file to create a global instance
* of your class
* - adjust the Makefile to include your class in SEARCH_OBJS
* - implement searchBestMove()
*
* Advises for implementation of searchBestMove():
* - call foundBestMove() when finding a best move since search start
* - call finishedNode() when finishing evaluation of a tree node
* - Use _maxDepth for strength level (maximal level searched in tree)
*/
class MinimaxStrategy: public SearchStrategy
{
public:
// Defines the name of the strategy
MinimaxStrategy(): SearchStrategy("MINIMAX") {}
// Factory method: just return a new instance of this class
SearchStrategy* clone() { return new MinimaxStrategy(); }
private:
/**
* Implementation of the strategy.
*/
void searchBestMove();
int minimax();
};
int current_depth=0;
#define MAX_DEPTH 3
int MinimaxStrategy::minimax()
{
Move m;
MoveList list;
// int maxEval, minEval;
int bestEval;
int eval;
int sign;
if(current_depth == MAX_DEPTH)
return evaluate();
bestEval = -17000;
// maxEval = -17000;
// minEval = 17000;
generateMoves(list);
if(evaluate() == 16000)
{
if(current_depth == 0)
finishedNode(0,0);
pretty_print("current_depth", current_depth);
return ((current_depth % 2) ==0) ? -16000 : 16000;
}
if((MAX_DEPTH-current_depth)%2 == 1)
sign = 1;
else
sign = -1;
while(list.getNext(m))
{
if(current_depth < MAX_DEPTH)
{
current_depth++;
playMove(m);
eval=minimax();
takeBack();
current_depth--;
}
if(sign*eval > bestEval)
{
bestEval = sign*eval;
if(unlikely(current_depth == 0)) {
pretty_print("Eval", bestEval);
foundBestMove(0, m, eval);
}
}
#if 0
if((MAX_DEPTH - current_depth +1) % 2 == 0)
{
if(eval > maxEval)
{
maxEval=eval;
if(current_depth == 0) {
pretty_print("Eval", eval);
foundBestMove(0, m, eval);
}
}
}
else
{
if(eval < minEval)
{
minEval=eval;
if(current_depth == 0) {
pretty_print("Eval2", eval);
foundBestMove(0, m, eval);
}
}
}
#endif
}
bestEval = sign*bestEval;
if(current_depth == 0)
finishedNode(0,0);
#if 0
if((MAX_DEPTH - current_depth +1) % 2 == 0)
return maxEval;
else
return minEval;
#endif
return bestEval;
}
void MinimaxStrategy::searchBestMove()
{
// KUKU : Here we have to implement the minimax strategy
// Minimax strategy tries to minimize the maximum possible outcome of opponent.
// At each turn, we check for each move the max positive outcome for opponent.
// We choose the move for which the max is least.
// To check this, we look at more than one levels in the Game Tree.
// we try to maximize bestEvaluation
/* int bestEval = minEvaluation();
int eval;
Move m;
MoveList list;
// generate list of allowed moves, put them into <list>
generateMoves(list);
// loop over all moves
while(list.getNext(m)) {
// draw move, evalute, and restore position
playMove(m);
eval = evaluate();
takeBack();
if (eval > bestEval) {
bestEval = eval;
foundBestMove(0, m, eval);
}
}
finishedNode(0,0);
*/
minimax();
}
// register ourselve as a search strategy
MinimaxStrategy minimaxStrategy;
/**
* Very simple example strategy:
* Search all possible positions reachable via one move,
* and return the move leading to best position
*
* (c) 2006, Josef Weidendorfer
*/
#include "search.h"
#include "board.h"
#include "eval.h"
/**
* To create your own search strategy:
* - copy this file into another one,
* - change the class name one the name given in constructor,
* - adjust clone() to return an instance of your class
* - adjust last line of this file to create a global instance
* of your class
* - adjust the Makefile to include your class in SEARCH_OBJS
* - implement searchBestMove()
*
* Advises for implementation of searchBestMove():
* - call foundBestMove() when finding a best move since search start
* - call finishedNode() when finishing evaluation of a tree node
* - Use _maxDepth for strength level (maximal level searched in tree)
*/
class OneLevelStrategy: public SearchStrategy
{
public:
// Defines the name of the strategy
OneLevelStrategy(): SearchStrategy("OneLevel") {}
// Factory method: just return a new instance of this class
SearchStrategy* clone() { return new OneLevelStrategy(); }
private:
/**
* Implementation of the strategy.
*/
void searchBestMove();
};
void OneLevelStrategy::searchBestMove()
{
// we try to maximize bestEvaluation
int bestEval = minEvaluation();
int eval;
Move m;
MoveList list;
// generate list of allowed moves, put them into <list>
generateMoves(list);
// loop over all moves
while(list.getNext(m)) {
// draw move, evalute, and restore position
playMove(m);
eval = evaluate();
takeBack();
if (eval > bestEval) {
bestEval = eval;
foundBestMove(0, m, eval);
}
}
finishedNode(0,0);
}
// register ourselve as a search strategy
OneLevelStrategy oneLevelStrategy;
/*
* Search the game play tree for move leading to
* position with highest evaluation
*
* (c) 2005, Josef Weidendorfer
*/
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <stdlib.h>
#include "board.h"
#include "search.h"
#include "eval.h"
/// SearchCallbacks
static struct timeval t1, t2;
static int kevalsPerSec = 30;
static int evalCounter = 0;
void SearchCallbacks::start(int msecsForSearch)
{
_leavesVisited = 0;
_nodesVisited = 0;
gettimeofday(&t1,0);
evalCounter = 0;
_msecsForSearch = msecsForSearch;
if (!_verbose) return;
if (_msecsForSearch>0)
printf(" Search started (ca. %d.%03d secs) ...\n",
_msecsForSearch / 1000, _msecsForSearch % 1000);
else
printf(" Search started ...\n");
}
void SearchCallbacks::substart(char* s)
{
if (!_verbose) return;
printf(" Subsearch %s ...\n", s);
}
int i=0;
unsigned int avg_kleavesPerSec = 0;
int _msecs;
void SearchCallbacks::finished(Move& m)
{
gettimeofday(&t2,0);
_msecsPassed =
(1000* t2.tv_sec + t2.tv_usec / 1000) -
(1000* t1.tv_sec + t1.tv_usec / 1000);
_msecs = _msecsPassed;
if (!_verbose) return;
if (_msecsPassed <1) _msecsPassed = 1;
if (_nodesVisited<1) _nodesVisited = 1;
printf(" Search finished after %d.%03d secs\n",
_msecsPassed / 1000, _msecsPassed % 1000);
printf(" Found move '%s'\n", m.name());
printf(" Leaves visited: %d (%d k/s) \n",
_leavesVisited, _leavesVisited /_msecsPassed);
printf(" Nodes visited: %d (%d leaves per node)\n",
_nodesVisited, _leavesVisited/_nodesVisited );
avg_kleavesPerSec = (i*avg_kleavesPerSec + _leavesVisited/_msecsPassed)/(i+1);
i++;
int eps = _leavesVisited /_msecsPassed;
if (eps>kevalsPerSec) kevalsPerSec = eps;
}
bool SearchCallbacks::afterEval()
{
_leavesVisited++;
/*
int ms = _msecsForSearch / 3;
if (ms > 500) ms = 500;
if (ms < 200) ms = 200;
evalCounter++;
if (evalCounter < ms * kevalsPerSec) return false;
// FIXME: Check for network events
evalCounter = 0;
gettimeofday(&t2,0);
_msecsPassed =
(1000* t2.tv_sec + t2.tv_usec / 1000) -
(1000* t1.tv_sec + t1.tv_usec / 1000);
if (_msecsPassed <1) _msecsPassed = 1;
if (_nodesVisited<1) _nodesVisited = 1;
int eps = _leavesVisited / _msecsPassed;
if (_verbose)
printf(" EvalRate %d k/s (%d evals, %d msecs)\n",
eps, _leavesVisited, _msecsPassed);
if (eps>kevalsPerSec) kevalsPerSec = eps;
if ((_msecsForSearch > 0) && (_msecsPassed > _msecsForSearch)) {
printf(" Stop!\n");
return true;
}
*/
return false;
}
void SearchCallbacks::foundBestMove(int d, const Move& m, int value)
{
if (d+2 >= _verbose) return;
static char* spaces = " ";
printf(" %sNew best move '%s', value %d ...\n",
spaces+20-d, m.name(), value);
}
int _leaveStart[10], _nodeStart[10];
void SearchCallbacks::startedNode(int d, char* s)
{
if (d+1 >= _verbose) return;
if (d<10) {
_leaveStart[d] = _leavesVisited;
_nodeStart[d] = _nodesVisited;
}
static char* spaces = " ";
printf(" %sStarted node at depth %d (%s)\n", spaces+20-d, d, s);
}
void SearchCallbacks::finishedNode(int d, Move* chain)
{
_nodesVisited++;
if (d+1 >= _verbose) return;
static char* spaces = " ";
printf(" %sFinished node at depth %d", spaces+20-d, d);
if (chain) {
int c = 0;
while( (c<4) && (chain->type != Move::none)) {
printf("%s%s", (c==0) ? " (" : ", ", chain->name());
chain++;
c++;
}
printf(")");
}
printf("\n");
if (d<10) {
int l = _leavesVisited - _leaveStart[d];
int n = _nodesVisited - _nodeStart[d];
if (n<1) n=1;
printf(" %s %d leaves, %d nodes visited (%d leaves per node)\n", spaces+20-d,
l,n, l/n);
}
}
/// SearchStrategy
static SearchStrategy* searchStrategies = 0;
SearchStrategy::SearchStrategy(char* n, int prio)
{
_maxDepth = 1;
_sc = 0;
_ev = 0;
_name = n;
_next = 0;
_prio = prio;
// register if not already registered
SearchStrategy *ss = searchStrategies, *prev = 0;
while(ss) {
if (strcmp(ss->_name, n) == 0) return;
if (ss->_prio > prio) break;
prev = ss;
ss = ss->_next;
}
if (prev) {
_next = prev->_next;
prev->_next = this;
}
else {
_next = searchStrategies;
searchStrategies = this;
}
}
char** SearchStrategy::strategies()
{
static char** sslist = 0;
int count = 0;
SearchStrategy* ss = searchStrategies;
while(ss) {
count++;
ss = ss->_next;
}
sslist = (char**) realloc(sslist, sizeof(char*) * (count+1) );
count = 0;
ss = searchStrategies;
while(ss) {
sslist[count] = ss->_name;
count++;
ss = ss->_next;
}
sslist[count] = 0;
return sslist;
}
SearchStrategy* SearchStrategy::create(char* n)
{
SearchStrategy* ss = searchStrategies;
while(ss) {
if (strcmp(ss->_name, n)==0) return ss;
ss = ss->_next;
}
return 0;
}
SearchStrategy* SearchStrategy::create(int i)
{
int count = 0;
SearchStrategy* ss = searchStrategies;
while(ss) {
if (count == i) return ss;
count++;
ss = ss->_next;
}
return 0;
}
Move& SearchStrategy::bestMove(Board* b)
{
if (_sc) {
int ms = b->msecsToPlay(b->actColor());
if (ms>0) {
int minTokens = b->getColor1Count();
int tokens = b->getColor2Count();
if (tokens < minTokens) minTokens = tokens;
int mvs = 60 - 10*(14-minTokens);
ms = ms/mvs;
}
_sc->start(ms);
}
_board = b;
_bestMove.type = Move::none;
_stopSearch = false;
searchBestMove();
if (_sc) _sc->finished(_bestMove);
return _bestMove;
}
Move& SearchStrategy::nextMove()
{
static Move m;
return m; // returns invalid
}
int SearchStrategy::evaluate()
{
int v = _ev->calcEvaluation(_board);
if (_sc) _stopSearch = _sc->afterEval();
return v;
}
int SearchStrategy::minEvaluation()
{
return _ev ? _ev->minValue() : -1;
}
int SearchStrategy::maxEvaluation()
{
return _ev ? _ev->maxValue() : -1;
}
void SearchStrategy::generateMoves(MoveList& list)
{
if (_board)
_board->generateMoves(list);
}
void SearchStrategy::playMove(const Move& m)
{
if (_board)
_board->playMove(m);
}
bool SearchStrategy::takeBack()
{
return _board ? _board->takeBack() : false;
}
void SearchStrategy::foundBestMove(int d, const Move& m, int eval)
{
if (d==0) _bestMove = m;
if (_sc)
_sc->foundBestMove(d, m, eval);
}
void SearchStrategy::finishedNode(int d, Move* bestList)
{
if (_sc)
_sc->finishedNode(d, bestList);
}
/*
* Search the game play tree for move leading to
* position with highest evaluation
*
* (c) 2005, Josef Weidendorfer
*/
#ifndef SEARCH_H
#define SEARCH_H
#include "move.h"
class Board;
class Evaluator;
class SearchStrategy;
class SearchCallbacks
{
public:
SearchCallbacks(int v = 0) { _verbose = v; }
virtual ~SearchCallbacks() {}
// called at beginning of new search. If <msecs> >0,
// we will stop search (via afterEval) after that time
virtual void start(int msecsForSearch);
// called at beginning of new sub search
virtual void substart(char*);
// called after search is done
virtual void finished(Move&);
// called after each evaluation
// returns true to request stop of search
virtual bool afterEval();
// called when a new best move is found at depth d
virtual void foundBestMove(int d, const Move&, int value);
// called before children are visited
virtual void startedNode(int d, char*);
/**
* Called after needed children are visited
* Second parameter gives array of best move sequence found
*/
virtual void finishedNode(int d, Move*);
int msecsPassed() { return _msecsPassed; }
int verbose() { return _verbose; }
int _leavesVisited, _nodesVisited;
private:
int _verbose;
int _msecsPassed, _msecsForSearch;
};
/*
* Base class for search strategies
*
* Implement searchBestMove !
*/
class SearchStrategy
{
public:
SearchStrategy(char* n, int prio = 5);
virtual ~SearchStrategy() {};
/* get list of names of available strategies */
static char** strategies();
/* factory for a named strategy */
static SearchStrategy* create(char*);
static SearchStrategy* create(int);
char* name() { return _name; }
void registerCallbacks(SearchCallbacks* sc) { _sc = sc; }
void setMaxDepth(int d) { _maxDepth = d; }
void setEvaluator(Evaluator* e) { _ev = e; }
/* Start search and return best move. */
Move& bestMove(Board*);
/* return best move in depth 1 if last search got one */
virtual Move& nextMove();
/* factory method: should return instance of derived class */
virtual SearchStrategy* clone() = 0;
void stopSearch() { _stopSearch = true; }
// protected:
/**
* Overwrite this to implement your search strategy
* and set _bestMove
*/
virtual void searchBestMove() = 0;
/**
* Some dispatcher methods for convenience.
* Call these from your search function
*/
int minEvaluation();
int maxEvaluation();
// see Board::generateMoves
void generateMoves(MoveList& list);
// see Board::playMove
void playMove(const Move& m);
// see Board::takeBack
bool takeBack();
// see SearchCallbacks::foundBestMove
void foundBestMove(int d, const Move& m, int eval);
// see SearchCallbacks::finishedNode
void finishedNode(int d, Move* bestList);
// see Evaluator::calcEvaluation
int evaluate();
int _maxDepth;
Board* _board;
bool _stopSearch;
SearchCallbacks* _sc;
Evaluator* _ev;
Move _bestMove;
private:
char* _name;
int _prio;
SearchStrategy* _next;
};
class ABIDStrategy: public SearchStrategy
{
public:
ABIDStrategy(): SearchStrategy("ABID", 2) {}
SearchStrategy* clone() { return new ABIDStrategy(); }
Move& nextMove() { return _pv[1]; }
/* recursive alpha/beta search */
int alphabeta(int depth, int alpha, int beta);
/* prinicipal variation found in last search */
Variation _pv;
int _currentMaxDepth;
private:
void searchBestMove();
int pv_split(int alpha0, int beta0);
Move _currentBestMove;
bool _inPV;
};
struct Slave_Input
{
int alpha, beta;
int depth;
int currentMaxDepth;
char boardstate[1024];
Move move;
};
struct Slave_Output
{
int eval;
int num_leaves, num_nodes;
Variation pv;
};
#endif
/**
* Send a start position into a game communication channel,
* and observe positions sent in the channel
*
* (C) 2005, Josef Weidendorfer
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "board.h"
#include "network.h"
/* Global, static vars */
static NetworkLoop l;
static Board b;
/* Start game? */
static bool start = true;
/* only show reachable positions with valid moves */
static bool onlyReachable = true;
/* time limit in seconds (0: no time limit, -1: not set) */
static int secsToPlay = -1;
/* to set verbosity of NetworkLoop implementation */
extern int verbose;
#define DEFAULT_DOMAIN_PORT 13133
/* remote channel */
static char* host = 0; /* not used on default */
static int rport = DEFAULT_DOMAIN_PORT;
/* local channel */
static int lport = DEFAULT_DOMAIN_PORT;
/* Where to read position to broadcast from? (0: start position) */
static FILE* file = 0;
class MyDomain: public NetworkDomain
{
public:
MyDomain(int p) : NetworkDomain(p) {}
void sendBoard();
protected:
void received(char* str);
void newConnection(Connection*);
};
void MyDomain::sendBoard()
{
static char tmp[500];
sprintf(tmp, "pos %s\n", b.getState());
printf(tmp+4);
int state = b.validState();
printf("%s\n", Board::stateDescription(state));
broadcast(tmp);
}
void MyDomain::received(char* str)
{
if (strncmp(str, "quit", 4)==0) {
l.exit();
return;
}
if (strncmp(str, "pos ", 4)!=0) return;
if (b.validState() != Board::empty) {
Board newBoard;
newBoard.setState(str+4);
Move m = b.moveToReach(&newBoard, false);
if (m.type == Move::none) {
printf("WARNING: Got a board which is not reachable via a valid move !?\n");
if (onlyReachable) return;
}
else {
if (b.actColor() == Board::color1)
printf("O draws move '%s'...\n", m.name());
else
printf("X draws move '%s'...\n", m.name());
}
}
b.setState(str+4);
printf(str+4);
int state = b.validState();
printf("%s\n", Board::stateDescription(state));
switch(state) {
case Board::timeout1:
case Board::timeout2:
case Board::win1:
case Board::win2:
l.exit();
default:
break;
}
}
void MyDomain::newConnection(Connection* c)
{
NetworkDomain::newConnection(c);
static char tmp[500];
int len = sprintf(tmp, "pos %s\n", b.getState());
c->sendString(tmp, len);
}
static void printHelp(char* prg, bool printHeader)
{
if (printHeader)
printf("Start V 0.2 - (C) 2005 Josef Weidendorfer\n"
"Broadcast a game position, observe the game and quit in winning state.\n\n");
printf("Usage: %s [options] [<file>|-]\n\n"
" <file> File containing start position (default: start position)\n"
" - Position is read from standard input\n\n",
prg);
printf(" Options:\n"
" -h / --help Print this help text\n"
" -v / -vv Be verbose / more verbose\n"
" -o Only observe, no start\n"
" -t <timeToPlay> Start in tournament modus (limited time)\n"
" -a Show all positions (default: only via valid moves)\n"
" -p [host:][port] Connection to broadcast channel\n"
" (default: %d)\n\n", DEFAULT_DOMAIN_PORT);
exit(1);
}
static void parseArgs(int argc, char* argv[])
{
int arg=0;
while(arg+1<argc) {
arg++;
if (argv[arg][0] == '-') {
if (strcmp(argv[arg],"-h")==0 ||
strcmp(argv[arg],"--help")==0) printHelp(argv[0], true);
if (strcmp(argv[arg],"-v")==0) {
verbose = 1;
continue;
}
if (strcmp(argv[arg],"-vv")==0) {
verbose = 2;
continue;
}
if (strcmp(argv[arg],"-o")==0) {
start = false;
continue;
}
if (strcmp(argv[arg],"-a")==0) {
onlyReachable = false;
continue;
}
if ((strcmp(argv[arg],"-t")==0) && (arg+1<argc)) {
arg++;
secsToPlay = atoi(argv[arg]);
if (secsToPlay == 0) {
printf("%s: WARNING - Ignoring tournament; %d secs to play\n",
argv[0], secsToPlay);
}
continue;
}
if ((strcmp(argv[arg],"-p")==0) && (arg+1<argc)) {
arg++;
if (argv[arg][0]>'0' && argv[arg][0]<='9') {
lport = atoi(argv[arg]);
continue;
}
char* c = strrchr(argv[arg],':');
int p = 0;
if (c != 0) {
*c = 0;
p = atoi(c+1);
}
host = argv[arg];
if (p) rport = p;
continue;
}
if (strcmp(argv[arg],"-")==0) {
file = stdin;
continue;
}
printf("%s: ERROR - Unknown option %s\n", argv[0], argv[arg]);
printHelp(argv[0], false);
}
file = fopen(argv[arg], "r");
if (!file) {
printf("%s: ERROR - Can not open '%s' for reading start position\n",
argv[0], argv[arg]);
printHelp(argv[0], false);
}
break;
}
}
int main(int argc, char* argv[])
{
parseArgs(argc, argv);
b.setVerbose(verbose);
MyDomain d(lport);
if (host) d.addConnection(host, rport);
l.install(&d);
if (start) {
if (file) {
char tmp[500];
int len = 0, c;
while( len<499 && (c=fgetc(file)) != EOF)
tmp[len++] = (char) c;
tmp[len++]=0;
printf("Gaurav\n");
printf("%s",tmp);
printf("Gaurav\n");
if (!b.setState(tmp)) {
printf("%s: WARNING - Can not parse given position; using start position\n", argv[0]);
b.begin(Board::color1);
}
}
else
b.begin(Board::color1);
if (secsToPlay >= 0) {
b.setMSecsToPlay(Board::color1, 1000 * secsToPlay);
b.setMSecsToPlay(Board::color2, 1000 * secsToPlay);
}
d.sendBoard();
}
return l.run();
}
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.7 //
ABIDStrategy search-abid.cpp /^ ABIDStrategy(): SearchStrategy("ABID", 2) {}$/;" f class:ABIDStrategy
ABIDStrategy search-abid.cpp /^class ABIDStrategy: public SearchStrategy$/;" c file:
ABIDStrategy search-parallel-abid.cpp /^ ABIDStrategy(): SearchStrategy("PARALLEL-ABID", 2) {}$/;" f class:ABIDStrategy
ABIDStrategy search-parallel-abid.cpp /^class ABIDStrategy: public SearchStrategy$/;" c file:
AllFields board.h /^ enum { AllFields = 121, \/* visible + ring of unvisible around *\/$/;" e enum:Board::__anon2
AllFields eval.h /^ enum { AllFields = 121, \/* visible + ring of unvisible around *\/$/;" e enum:Evaluator::__anon5
BOARD_H board.h 10;" d
Board board.cpp /^Board::Board()$/;" f class:Board
Board board.h /^class Board$/;" c
CHECK board.cpp 21;" d file:
CXX Makefile /^CXX = mpiCC$/;" m
CXXFLAGS Makefile /^CXXFLAGS=-O3$/;" m
Connection network.cpp /^Connection::Connection(NetworkDomain* d, Connection* n,$/;" f class:Connection
Connection network.h /^class Connection {$/;" c
DEFAULT_DOMAIN_DIFF referee.cpp 49;" d file:
DEFAULT_DOMAIN_PORT referee.cpp 48;" d file:
DEFAULT_DOMAIN_PORT start.cpp 32;" d file:
EVAL_H eval.h 17;" d
EvalScheme eval.cpp /^EvalScheme::EvalScheme(char* file)$/;" f class:EvalScheme
EvalScheme eval.h /^class EvalScheme$/;" c
Evaluator eval.cpp /^Evaluator::Evaluator()$/;" f class:Evaluator
Evaluator eval.h /^class Evaluator$/;" c
ID network.h /^ int ID() { return myID; }$/;" f class:NetworkDomain
InARowType board.h /^ enum InARowType { inARow2 = 0, inARow3, inARow4, inARow5, inARowCount };$/;" g class:MoveCounter
LDFLAGS Makefile /^LDFLAGS=$/;" m
LIB_OBJS Makefile /^LIB_OBJS = move.o board.o network.o search.o eval.o$/;" m
Left move.h /^ enum { Right=1, RightDown, LeftDown, Left, LeftUp, RightUp };$/;" e enum:Move::__anon6
LeftDown move.h /^ enum { Right=1, RightDown, LeftDown, Left, LeftUp, RightUp };$/;" e enum:Move::__anon6
LeftUp move.h /^ enum { Right=1, RightDown, LeftDown, Left, LeftUp, RightUp };$/;" e enum:Move::__anon6
MAX_DEPTH search-minimax.cpp 52;" d file:
MAX_DEPTH search-parallel-minimax.cpp 59;" d file:
MOVE_H move.h 12;" d
MaxMoves move.h /^ enum { MaxMoves = 150 };$/;" e enum:MoveList::__anon8
MinimaxStrategy search-minimax.cpp /^ MinimaxStrategy(): SearchStrategy("MINIMAX") {}$/;" f class:MinimaxStrategy
MinimaxStrategy search-minimax.cpp /^class MinimaxStrategy: public SearchStrategy$/;" c file:
MinimaxStrategy search-parallel-minimax.cpp /^ MinimaxStrategy(): SearchStrategy("PARALLEL-MINIMAX") {}$/;" f class:MinimaxStrategy
MinimaxStrategy search-parallel-minimax.cpp /^class MinimaxStrategy: public SearchStrategy$/;" c file:
Move move.h /^ Move() { type = none; field = 0; direction = 0; }$/;" f class:Move
Move move.h /^ Move(short f, char d, MoveType t)$/;" f class:Move
Move move.h /^class Move$/;" c
MoveCounter board.cpp /^MoveCounter::MoveCounter()$/;" f class:MoveCounter
MoveCounter board.h /^class MoveCounter$/;" c
MoveList move.cpp /^MoveList::MoveList()$/;" f class:MoveList
MoveList move.h /^class MoveList$/;" c
MoveType move.h /^ enum MoveType { out2 = 0, out1with3, out1with2, push2,$/;" g class:Move
MvsStored board.h /^ MvsStored = 100 };$/;" e enum:Board::__anon2
MvsStored eval.h /^ MvsStored = 100 };$/;" e enum:Evaluator::__anon5
MyDomain player.cpp /^ MyDomain(int p) : NetworkDomain(p) {}$/;" f class:MyDomain
MyDomain player.cpp /^class MyDomain: public NetworkDomain$/;" c file:
MyDomain referee.cpp /^ MyDomain(int p) : NetworkDomain(p) {}$/;" f class:MyDomain
MyDomain referee.cpp /^class MyDomain: public NetworkDomain$/;" c file:
MyDomain start.cpp /^ MyDomain(int p) : NetworkDomain(p) {}$/;" f class:MyDomain
MyDomain start.cpp /^class MyDomain: public NetworkDomain$/;" c file:
NETWORK_H network.h 13;" d
NetworkDomain network.cpp /^NetworkDomain::NetworkDomain(int id)$/;" f class:NetworkDomain
NetworkDomain network.h /^class NetworkDomain$/;" c
NetworkLoop network.cpp /^NetworkLoop::NetworkLoop()$/;" f class:NetworkLoop
NetworkLoop network.h /^class NetworkLoop$/;" c
NetworkTimer network.cpp /^NetworkTimer::NetworkTimer(int msecs)$/;" f class:NetworkTimer
NetworkTimer network.h /^class NetworkTimer$/;" c
OneLevelStrategy search-onelevel.cpp /^ OneLevelStrategy(): SearchStrategy("OneLevel") {}$/;" f class:OneLevelStrategy
OneLevelStrategy search-onelevel.cpp /^class OneLevelStrategy: public SearchStrategy$/;" c file:
RealFields board.h /^ RealFields = 61, \/* number of visible fields *\/$/;" e enum:Board::__anon2
RealFields eval.h /^ RealFields = 61, \/* number of visible fields *\/$/;" e enum:Evaluator::__anon5
Right move.h /^ enum { Right=1, RightDown, LeftDown, Left, LeftUp, RightUp };$/;" e enum:Move::__anon6
RightDown move.h /^ enum { Right=1, RightDown, LeftDown, Left, LeftUp, RightUp };$/;" e enum:Move::__anon6
RightUp move.h /^ enum { Right=1, RightDown, LeftDown, Left, LeftUp, RightUp };$/;" e enum:Move::__anon6
SEARCH_H search.h 9;" d
SEARCH_OBJS Makefile /^SEARCH_OBJS = $(LIB_OBJS) search-parallel-minimax.o search-parallel-abid.cpp$/;" m
SearchCallbacks search.h /^ SearchCallbacks(int v = 0) { _verbose = v; }$/;" f class:SearchCallbacks
SearchCallbacks search.h /^class SearchCallbacks$/;" c
SearchStrategy search.cpp /^SearchStrategy::SearchStrategy(char* n, int prio)$/;" f class:SearchStrategy
SearchStrategy search.h /^class SearchStrategy$/;" c
Variation move.h /^ Variation() { clear(1); }$/;" f class:Variation
Variation move.h /^class Variation$/;" c
_bestMove search.h /^ Move _bestMove;$/;" m class:SearchStrategy
_board eval.h /^ Board* _board;$/;" m class:Evaluator
_board search.h /^ Board* _board;$/;" m class:SearchStrategy
_currentBestMove search-abid.cpp /^ Move _currentBestMove;$/;" m class:ABIDStrategy file:
_currentBestMove search-parallel-abid.cpp /^ Move _currentBestMove;$/;" m class:ABIDStrategy file:
_currentMaxDepth search-abid.cpp /^ int _currentMaxDepth;$/;" m class:ABIDStrategy file:
_currentMaxDepth search-parallel-abid.cpp /^ int _currentMaxDepth;$/;" m class:ABIDStrategy file:
_ev board.h /^ Evaluator* _ev;$/;" m class:Board
_ev search.h /^ Evaluator* _ev;$/;" m class:SearchStrategy
_evalScheme eval.h /^ EvalScheme* _evalScheme;$/;" m class:Evaluator
_inARowValue eval.h /^ int _inARowValue[MoveCounter::inARowCount];$/;" m class:EvalScheme
_inPV search-abid.cpp /^ bool _inPV;$/;" m class:ABIDStrategy file:
_inPV search-parallel-abid.cpp /^ bool _inPV;$/;" m class:ABIDStrategy file:
_leaveStart search.cpp /^int _leaveStart[10], _nodeStart[10];$/;" v
_leavesVisited search.h /^ int _leavesVisited, _nodesVisited;$/;" m class:SearchCallbacks
_left network.h /^ struct timeval _left;$/;" m class:NetworkTimer typeref:struct:NetworkTimer::timeval
_maxDepth search.h /^ int _maxDepth;$/;" m class:SearchStrategy
_moveCount board.h /^ int _moveCount[Move::typeCount];$/;" m class:MoveCounter
_moveNo board.h /^ int _moveNo; \/* move number in current game *\/$/;" m class:Board
_moveValue eval.h /^ int _stoneValue[6], _moveValue[Move::none];$/;" m class:EvalScheme
_msecs network.h /^ int _msecs;$/;" m class:NetworkTimer
_msecsForSearch search.h /^ int _msecsPassed, _msecsForSearch;$/;" m class:SearchCallbacks
_msecsPassed search.h /^ int _msecsPassed, _msecsForSearch;$/;" m class:SearchCallbacks
_msecsToPlay board.h /^ int _msecsToPlay[3]; \/* time in seconds to play *\/$/;" m class:Board
_name search.h /^ char* _name;$/;" m class:SearchStrategy
_next search.h /^ SearchStrategy* _next;$/;" m class:SearchStrategy
_nodeStart search.cpp /^int _leaveStart[10], _nodeStart[10];$/;" v
_nodesVisited search.h /^ int _leavesVisited, _nodesVisited;$/;" m class:SearchCallbacks
_prio search.h /^ int _prio;$/;" m class:SearchStrategy
_pv search-abid.cpp /^ Variation _pv;$/;" m class:ABIDStrategy file:
_pv search-parallel-abid.cpp /^ Variation _pv;$/;" m class:ABIDStrategy file:
_ringDiff eval.h /^ int _ringValue[5], _ringDiff[5];$/;" m class:EvalScheme
_ringValue eval.h /^ int _ringValue[5], _ringDiff[5];$/;" m class:EvalScheme
_rowCount board.h /^ int _rowCount[inARowCount];$/;" m class:MoveCounter
_sc search.h /^ SearchCallbacks* _sc;$/;" m class:SearchStrategy
_ss board.h /^ SearchStrategy* _ss;$/;" m class:Board
_stoneValue eval.h /^ int _stoneValue[6], _moveValue[Move::none];$/;" m class:EvalScheme
_stopSearch search.h /^ bool _stopSearch;$/;" m class:SearchStrategy
_verbose board.h /^ int _verbose;$/;" m class:Board
_verbose search.h /^ int _verbose;$/;" m class:SearchCallbacks
abidStrategy search-abid.cpp /^ABIDStrategy abidStrategy;$/;" v
abidStrategy search-parallel-abid.cpp /^ABIDStrategy abidStrategy;$/;" v
actColor board.h /^ int actColor() const$/;" f class:Board
actMaxDepth move.h /^ int actMaxDepth;$/;" m class:Variation
actual move.h /^ int actual[Move::typeCount];$/;" m class:MoveList
actualType move.h /^ int nextUnused, actualType;$/;" m class:MoveList
addConnection network.cpp /^void NetworkDomain::addConnection(const char* host, int port)$/;" f class:NetworkDomain
addr network.cpp /^char* Connection::addr()$/;" f class:Connection
afterEval search.cpp /^bool SearchCallbacks::afterEval()$/;" f class:SearchCallbacks
all move.h /^ enum { all , start1, start2, start3 };$/;" e enum:MoveList::__anon9
alphabeta search-abid.cpp /^int ABIDStrategy::alphabeta(int depth, int alpha, int beta)$/;" f class:ABIDStrategy
alphabeta search-parallel-abid.cpp /^int ABIDStrategy::alphabeta(int depth, int alpha, int beta)$/;" f class:ABIDStrategy
avg_kleavesPerSec search.cpp /^unsigned int avg_kleavesPerSec = 0;$/;" v
b player.cpp /^Board b;$/;" v
b referee.cpp /^static Board b;$/;" v file:
b start.cpp /^static Board b;$/;" v file:
bUpdateSpy board.h /^ bool show, bUpdateSpy;$/;" m class:Board
begin board.cpp /^void Board::begin(int startColor)$/;" f class:Board
bestMove board.cpp /^Move& Board::bestMove()$/;" f class:Board
bestMove search.cpp /^Move& SearchStrategy::bestMove(Board* b)$/;" f class:SearchStrategy
broadcast network.cpp /^void NetworkDomain::broadcast(const char* str)$/;" f class:NetworkDomain
calcEvaluation eval.cpp /^int Evaluator::calcEvaluation(Board* b)$/;" f class:Evaluator
chain move.h /^ Move* chain(int d)$/;" f class:Variation
changeEval player.cpp /^bool changeEval = true;$/;" v
changeEvaluation eval.cpp /^void Evaluator::changeEvaluation()$/;" f class:Evaluator
check network.cpp /^void NetworkDomain::check(fd_set* set)$/;" f class:NetworkDomain
clear board.cpp /^void Board::clear()$/;" f class:Board
clear move.cpp /^void MoveList::clear()$/;" f class:MoveList
clear move.cpp /^void Variation::clear(int d)$/;" f class:Variation
clone search-abid.cpp /^ SearchStrategy* clone() { return new ABIDStrategy(); }$/;" f class:ABIDStrategy
clone search-minimax.cpp /^ SearchStrategy* clone() { return new MinimaxStrategy(); }$/;" f class:MinimaxStrategy
clone search-onelevel.cpp /^ SearchStrategy* clone() { return new OneLevelStrategy(); }$/;" f class:OneLevelStrategy
clone search-parallel-abid.cpp /^ SearchStrategy* clone() { return new ABIDStrategy(); }$/;" f class:ABIDStrategy
clone search-parallel-minimax.cpp /^ SearchStrategy* clone() { return new MinimaxStrategy(); }$/;" f class:MinimaxStrategy
close network.cpp /^void NetworkDomain::close()$/;" f class:NetworkDomain
color board.h /^ int color; \/* actual color *\/$/;" m class:Board
color1 board.h /^ color1, color2, color1bright, color2bright$/;" e enum:Board::__anon1
color1 eval.h /^ color1, color2, color1bright, color2bright$/;" e enum:Evaluator::__anon4
color1Count board.h /^ int color1Count, color2Count;$/;" m class:Board
color1bright board.h /^ color1, color2, color1bright, color2bright$/;" e enum:Board::__anon1
color1bright eval.h /^ color1, color2, color1bright, color2bright$/;" e enum:Evaluator::__anon4
color2 board.h /^ color1, color2, color1bright, color2bright$/;" e enum:Board::__anon1
color2 eval.h /^ color1, color2, color1bright, color2bright$/;" e enum:Evaluator::__anon4
color2Count board.h /^ int color1Count, color2Count;$/;" m class:Board
color2bright board.h /^ color1, color2, color1bright, color2bright$/;" e enum:Board::__anon1
color2bright eval.h /^ color1, color2, color1bright, color2bright$/;" e enum:Evaluator::__anon4
connectionList network.h /^ Connection* connectionList;$/;" m class:NetworkDomain
count move.cpp /^int MoveList::count(int maxType)$/;" f class:MoveList
count network.cpp /^int NetworkDomain::count()$/;" f class:NetworkDomain
countFrom board.cpp /^void Board::countFrom(int startField, int color,$/;" f class:Board
create search.cpp /^SearchStrategy* SearchStrategy::create(char* n)$/;" f class:SearchStrategy
create search.cpp /^SearchStrategy* SearchStrategy::create(int i)$/;" f class:SearchStrategy
current_depth search-minimax.cpp /^int current_depth=0;$/;" v
current_depth search-parallel-minimax.cpp /^int current_depth=0;$/;" v
d1 referee.cpp /^static MyDomain *d1 = 0, *d2 = 0;$/;" v file:
d1MemberExists referee.cpp /^static bool d1MemberExists = false;$/;" v file:
d2 referee.cpp /^static MyDomain *d1 = 0, *d2 = 0;$/;" v file:
d2MemberExists referee.cpp /^static bool d2MemberExists = false;$/;" v file:
defaultInARowValue eval.cpp /^static int defaultInARowValue[MoveCounter::inARowCount]= { 2, 5, 4, 3 };$/;" v file:
defaultMoveValue eval.cpp /^static int defaultMoveValue[Move::typeCount] = { 40,30,30, 15,14,13, $/;" v file:
defaultPort network.h /^ enum { defaultPort = 23412 };$/;" e enum:NetworkDomain::__anon11
defaultRingDiff eval.cpp /^static int defaultRingDiff[] = { 0, 10, 10, 8, 5 };$/;" v file:
defaultRingValue eval.cpp /^static int defaultRingValue[] = { 45, 35, 25, 10, 0 };$/;" v file:
defaultStoneValue eval.cpp /^static int defaultStoneValue[]= { 0,-800,-1800,-3000,-4400,-6000 };$/;" v file:
direction board.cpp /^int Board::direction[]= { -11,1,12,11,-1,-12,-11,1 };$/;" m class:Board file:
direction board.h /^ static int direction[8];$/;" m class:Board
direction move.h /^ unsigned char direction;$/;" m class:Move
domain network.h /^ NetworkDomain* domain;$/;" m class:Connection
domainList network.h /^ NetworkDomain* domainList;$/;" m class:NetworkLoop
empty board.h /^ enum { empty=0, $/;" e enum:Board::__anon3
ev player.cpp /^Evaluator ev;$/;" v
evalCounter search.cpp /^static int evalCounter = 0;$/;" v file:
evalScheme eval.h /^ EvalScheme* evalScheme() { return _evalScheme; }$/;" f class:Evaluator
evaluate search.cpp /^int SearchStrategy::evaluate()$/;" f class:SearchStrategy
exit network.cpp /^void NetworkLoop::exit(int v)$/;" f class:NetworkLoop
exit_loop network.h /^ bool exit_loop;$/;" m class:NetworkLoop
exit_value network.h /^ int exit_value;$/;" m class:NetworkLoop
fd network.h /^ int fd, myID, myPort;$/;" m class:NetworkDomain
field board.h /^ int field[AllFields]; \/* actual board *\/$/;" m class:Board
field eval.h /^ int* field;$/;" m class:Evaluator
field move.h /^ short field;$/;" m class:Move
fieldArray board.h /^ int* fieldArray() { return field; }$/;" f class:Board
fieldDiffOfDir board.h /^ static int fieldDiffOfDir(int d) { return direction[d]; }$/;" f class:Board
fieldValue eval.cpp /^int Evaluator::fieldValue[61];$/;" m class:Evaluator file:
fieldValue eval.h /^ static int fieldValue[Board::RealFields];$/;" m class:Evaluator
file referee.cpp /^static FILE* file = 0;$/;" v file:
file start.cpp /^static FILE* file = 0;$/;" v file:
finished search.cpp /^void SearchCallbacks::finished(Move& m)$/;" f class:SearchCallbacks
finishedNode search.cpp /^void SearchCallbacks::finishedNode(int d, Move* chain)$/;" f class:SearchCallbacks
finishedNode search.cpp /^void SearchStrategy::finishedNode(int d, Move* bestList)$/;" f class:SearchStrategy
first move.h /^ int first[Move::typeCount];$/;" m class:MoveList
foundBestMove search.cpp /^void SearchCallbacks::foundBestMove(int d, const Move& m, int value)$/;" f class:SearchCallbacks
foundBestMove search.cpp /^void SearchStrategy::foundBestMove(int d, const Move& m, int eval)$/;" f class:SearchStrategy
free board.h /^ out = 10, free = 0,$/;" e enum:Board::__anon1
free eval.h /^ out = 10, free = 0,$/;" e enum:Evaluator::__anon4
generateFieldMoves board.cpp /^void Board::generateFieldMoves(int startField, MoveList& list)$/;" f class:Board
generateMoves board.cpp /^void Board::generateMoves(MoveList& list)$/;" f class:Board
generateMoves search.cpp /^void SearchStrategy::generateMoves(MoveList& list)$/;" f class:SearchStrategy
getColor1Count board.h /^ int getColor1Count() { return color1Count; }$/;" f class:Board
getColor2Count board.h /^ int getColor2Count() { return color2Count; }$/;" f class:Board
getLength move.h /^ int getLength()$/;" f class:MoveList
getNewConnection network.cpp /^Connection* NetworkDomain::getNewConnection(const char* h,$/;" f class:NetworkDomain
getNext move.cpp /^bool MoveList::getNext(Move& m, int maxType)$/;" f class:MoveList
getState board.cpp /^char* Board::getState()$/;" f class:Board
gotConnection network.cpp /^void NetworkDomain::gotConnection()$/;" f class:NetworkDomain
hasMove move.h /^ bool hasMove(int d)$/;" f class:Variation
hasSameFields board.cpp /^bool Board::hasSameFields(Board* b)$/;" f class:Board
host network.h /^ char host[100];$/;" m class:Connection
host player.cpp /^char* host = 0; \/* not used on default *\/$/;" v
host referee.cpp /^static char* host[2] = {0,0}; \/* not used per default *\/$/;" v file:
host start.cpp /^static char* host = 0; \/* not used on default *\/$/;" v file:
i search.cpp /^int i=0;$/;" v
inARow2 board.h /^ enum InARowType { inARow2 = 0, inARow3, inARow4, inARow5, inARowCount };$/;" e enum:MoveCounter::InARowType
inARow3 board.h /^ enum InARowType { inARow2 = 0, inARow3, inARow4, inARow5, inARowCount };$/;" e enum:MoveCounter::InARowType
inARow4 board.h /^ enum InARowType { inARow2 = 0, inARow3, inARow4, inARow5, inARowCount };$/;" e enum:MoveCounter::InARowType
inARow5 board.h /^ enum InARowType { inARow2 = 0, inARow3, inARow4, inARow5, inARowCount };$/;" e enum:MoveCounter::InARowType
inARowCount board.h /^ enum InARowType { inARow2 = 0, inARow3, inARow4, inARow5, inARowCount };$/;" e enum:MoveCounter::InARowType
inARowValue eval.h /^ int inARowValue(int s)$/;" f class:EvalScheme
incRow board.h /^ void incRow(int r) { _rowCount[r]++; }$/;" f class:MoveCounter
incType board.h /^ void incType(int t) { _moveCount[t]++; }$/;" f class:MoveCounter
init board.cpp /^void MoveCounter::init()$/;" f class:MoveCounter
insert move.cpp /^void MoveList::insert(Move m)$/;" f class:MoveList
insert move.h /^ void insert(short f, char d, Move::MoveType t)$/;" f class:MoveList
install network.cpp /^bool NetworkLoop::install(NetworkDomain* d)$/;" f class:NetworkLoop
install network.cpp /^bool NetworkLoop::install(NetworkTimer* t)$/;" f class:NetworkLoop
invalid board.h /^ invalid };$/;" e enum:Board::__anon3
isConsistent board.cpp /^bool Board::isConsistent()$/;" f class:Board
isElement move.cpp /^bool MoveList::isElement(Move &m, int startType, bool del)$/;" f class:MoveList
isElement move.cpp /^bool MoveList::isElement(int f)$/;" f class:MoveList
isListening network.h /^ bool isListening() { return (fd>=0); }$/;" f class:NetworkDomain
isOutMove move.h /^ bool isOutMove() const { return type <= out1with2; }$/;" f class:Move
isPushMove move.h /^ bool isPushMove() const { return type <= push1with2; }$/;" f class:Move
isValid board.h /^ bool isValid() { return (color1Count>8 && color2Count>8); }$/;" f class:Board
kevalsPerSec search.cpp /^static int kevalsPerSec = 30;$/;" v file:
l player.cpp /^NetworkLoop l;$/;" v
l referee.cpp /^static NetworkLoop l;$/;" v file:
l start.cpp /^static NetworkLoop l;$/;" v file:
last move.h /^ int last[Move::typeCount];$/;" m class:MoveList
lastMove board.h /^ Move& lastMove()$/;" f class:Board
left2 move.h /^ left2, right2, move2, move1, none };$/;" e enum:Move::MoveType
left3 move.h /^ push1with3, push1with2, move3, left3, right3,$/;" e enum:Move::MoveType
likely search-minimax.cpp 15;" d file:
likely search-parallel-minimax.cpp 17;" d file:
listeningFD network.h /^ int listeningFD() { return fd; }$/;" f class:NetworkDomain
listeningPort network.h /^ int listeningPort() { return myPort; }$/;" f class:NetworkDomain
loop network.h /^ NetworkLoop* loop;$/;" m class:NetworkDomain
lport player.cpp /^int lport = 13133;$/;" v
lport referee.cpp /^static int lport[2] = {DEFAULT_DOMAIN_PORT, DEFAULT_DOMAIN_PORT + DEFAULT_DOMAIN_DIFF};$/;" v file:
lport start.cpp /^static int lport = DEFAULT_DOMAIN_PORT;$/;" v file:
main player.cpp /^int main(int argc, char* argv[])$/;" f
main referee.cpp /^int main(int argc, char* argv[])$/;" f
main start.cpp /^int main(int argc, char* argv[])$/;" f
maxDepth move.h /^ enum { maxDepth = 10 };$/;" e enum:Variation::__anon10
maxDepth player.cpp /^int maxDepth = 0;$/;" v
maxEvaluation search.cpp /^int SearchStrategy::maxEvaluation()$/;" f class:SearchStrategy
maxMoveType move.h /^ maxMoveType = move1 };$/;" e enum:Move::__anon7
maxMoves player.cpp /^int maxMoves = -1;$/;" v
maxOutType move.h /^ maxOutType = out1with2,$/;" e enum:Move::__anon7
maxPushType move.h /^ maxPushType = push1with2,$/;" e enum:Move::__anon7
maxValue eval.h /^ int maxValue() { return 15000; }$/;" f class:Evaluator
max_readfd network.h /^ int max_readfd;$/;" m class:NetworkLoop
minEvaluation search.cpp /^int SearchStrategy::minEvaluation()$/;" f class:SearchStrategy
minLeft network.cpp /^void NetworkTimer::minLeft(struct timeval* tv)$/;" f class:NetworkTimer
minValue eval.h /^ int minValue() { return -15000; }$/;" f class:Evaluator
minimax search-minimax.cpp /^int MinimaxStrategy::minimax()$/;" f class:MinimaxStrategy
minimax search-parallel-minimax.cpp /^int MinimaxStrategy::minimax()$/;" f class:MinimaxStrategy
minimaxStrategy search-minimax.cpp /^MinimaxStrategy minimaxStrategy;$/;" v
minimaxStrategy search-parallel-minimax.cpp /^MinimaxStrategy minimaxStrategy;$/;" v
move move.h /^ Move move[MaxMoves];$/;" m class:MoveList
move move.h /^ Move move[maxDepth][maxDepth];$/;" m class:Variation
move1 move.h /^ left2, right2, move2, move1, none };$/;" e enum:Move::MoveType
move2 move.h /^ left2, right2, move2, move1, none };$/;" e enum:Move::MoveType
move3 move.h /^ push1with3, push1with2, move3, left3, right3,$/;" e enum:Move::MoveType
moveCount board.h /^ int moveCount(int t) { return _moveCount[t]; }$/;" f class:MoveCounter
moveNo board.h /^ int moveNo() { return _moveNo; }$/;" f class:Board
moveSum board.cpp /^int MoveCounter::moveSum()$/;" f class:MoveCounter
moveToReach board.cpp /^Move Board::moveToReach(Board* b, bool fuzzy)$/;" f class:Board
moveValue eval.h /^ int moveValue(int t)$/;" f class:EvalScheme
movesStored board.cpp /^int Board::movesStored()$/;" f class:Board
msecs network.h /^ int msecs() { return _msecs; }$/;" f class:NetworkTimer
msecsPassed search.h /^ int msecsPassed() { return _msecsPassed; }$/;" f class:SearchCallbacks
msecsToPlay board.h /^ int msecsToPlay(int c) { return _msecsToPlay[c]; }$/;" f class:Board
msecsToPlay referee.cpp /^static int msecsToPlay[3] = {0,0,0};$/;" v file:
myColor player.cpp /^int myColor = Board::color1;$/;" v
myID network.h /^ int fd, myID, myPort;$/;" m class:NetworkDomain
myPort network.h /^ int fd, myID, myPort;$/;" m class:NetworkDomain
mySin network.h /^ struct sockaddr_in mySin;$/;" m class:NetworkDomain typeref:struct:NetworkDomain::sockaddr_in
name move.cpp /^char* Move::name() const$/;" f class:Move
name search.h /^ char* name() { return _name; }$/;" f class:SearchStrategy
nameOfDir move.cpp /^static const char* nameOfDir(int dir)$/;" f file:
nameOfPos move.cpp /^static char* nameOfPos(int p)$/;" f file:
newConnection network.cpp /^void NetworkDomain::newConnection(Connection* c)$/;" f class:NetworkDomain
newConnection referee.cpp /^void MyDomain::newConnection(Connection* c)$/;" f class:MyDomain
newConnection start.cpp /^void MyDomain::newConnection(Connection* c)$/;" f class:MyDomain
next move.h /^ int next[MaxMoves];$/;" m class:MoveList
next network.h /^ Connection* next;$/;" m class:Connection
next network.h /^ NetworkTimer* next;$/;" m class:NetworkTimer
next network.h /^ NetworkDomain* next;$/;" m class:NetworkDomain
nextMove board.cpp /^Move& Board::nextMove()$/;" f class:Board
nextMove search-abid.cpp /^ Move& nextMove() { return _pv[1]; }$/;" f class:ABIDStrategy
nextMove search-parallel-abid.cpp /^ Move& nextMove() { return _pv[1]; }$/;" f class:ABIDStrategy
nextMove search.cpp /^Move& SearchStrategy::nextMove()$/;" f class:SearchStrategy
nextUnused move.h /^ int nextUnused, actualType;$/;" m class:MoveList
none move.h /^ left2, right2, move2, move1, none };$/;" e enum:Move::MoveType
num_threads player.cpp /^int num_threads;$/;" v
oneLevelStrategy search-onelevel.cpp /^OneLevelStrategy oneLevelStrategy;$/;" v
onlyReachable start.cpp /^static bool onlyReachable = true;$/;" v file:
operator [] board.h /^inline int Board::operator[](int no) const$/;" f class:Board
operator [] move.h /^ Move& operator[](int i)$/;" f class:Variation
order board.cpp /^int Board::order[]={$/;" m class:Board file:
order board.h /^ static int order[RealFields];$/;" m class:Board
out board.h /^ out = 10, free = 0,$/;" e enum:Board::__anon1
out eval.h /^ out = 10, free = 0,$/;" e enum:Evaluator::__anon4
out1with2 move.h /^ enum MoveType { out2 = 0, out1with3, out1with2, push2,$/;" e enum:Move::MoveType
out1with3 move.h /^ enum MoveType { out2 = 0, out1with3, out1with2, push2,$/;" e enum:Move::MoveType
out2 move.h /^ enum MoveType { out2 = 0, out1with3, out1with2, push2,$/;" e enum:Move::MoveType
parseArgs player.cpp /^void parseArgs(int argc, char* argv[])$/;" f
parseArgs referee.cpp /^static void parseArgs(int argc, char* argv[])$/;" f file:
parseArgs start.cpp /^static void parseArgs(int argc, char* argv[])$/;" f file:
pending network.cpp /^bool NetworkLoop::pending()$/;" f class:NetworkLoop
playMove board.cpp /^void Board::playMove(const Move& m, int msecs)$/;" f class:Board
playMove search.cpp /^void SearchStrategy::playMove(const Move& m)$/;" f class:SearchStrategy
port network.h /^ int port;$/;" m class:Connection
prepareConnection network.cpp /^Connection* NetworkDomain::prepareConnection(const char* host, int port)$/;" f class:NetworkDomain
pretty_print player.cpp 24;" d file:
pretty_print search-minimax.cpp 13;" d file:
pretty_print search-parallel-abid.cpp 15;" d file:
pretty_print search-parallel-minimax.cpp 15;" d file:
print board.cpp /^void Board::print()$/;" f class:Board
print move.cpp /^void Move::print() const$/;" f class:Move
printHelp player.cpp /^void printHelp(char* prg, bool printHeader)$/;" f
printHelp referee.cpp /^static void printHelp(char* prg, bool printHeader)$/;" f file:
printHelp start.cpp /^static void printHelp(char* prg, bool printHeader)$/;" f file:
processPending network.cpp /^void NetworkLoop::processPending()$/;" f class:NetworkLoop
push1with2 move.h /^ push1with3, push1with2, move3, left3, right3,$/;" e enum:Move::MoveType
push1with3 move.h /^ push1with3, push1with2, move3, left3, right3,$/;" e enum:Move::MoveType
push2 move.h /^ enum MoveType { out2 = 0, out1with3, out1with2, push2,$/;" e enum:Move::MoveType
randomMove board.cpp /^Move Board::randomMove()$/;" f class:Board
reachable network.h /^ bool reachable;$/;" m class:Connection
read eval.cpp /^void EvalScheme::read(char* file)$/;" f class:EvalScheme
readfds network.h /^ fd_set readfds;$/;" m class:NetworkLoop
received network.cpp /^void NetworkDomain::received(char* str)$/;" f class:NetworkDomain
received player.cpp /^void MyDomain::received(char* str)$/;" f class:MyDomain
received referee.cpp /^void MyDomain::received(char* str)$/;" f class:MyDomain
received start.cpp /^void MyDomain::received(char* str)$/;" f class:MyDomain
registerCallbacks search.h /^ void registerCallbacks(SearchCallbacks* sc) { _sc = sc; }$/;" f class:SearchStrategy
remove network.cpp /^void NetworkLoop::remove(NetworkDomain* domain)$/;" f class:NetworkLoop
reset network.cpp /^void NetworkTimer::reset()$/;" f class:NetworkTimer
right2 move.h /^ left2, right2, move2, move1, none };$/;" e enum:Move::MoveType
right3 move.h /^ push1with3, push1with2, move3, left3, right3,$/;" e enum:Move::MoveType
ringDiff eval.h /^ int ringDiff(int r) { return (r>0 && r<5) ? _ringDiff[r] : 0; }$/;" f class:EvalScheme
ringValue eval.h /^ int ringValue(int r) { return (r>=0 && r<5) ? _ringValue[r] : 0; }$/;" f class:EvalScheme
rowCount board.h /^ int rowCount(int r) { return _rowCount[r]; }$/;" f class:MoveCounter
rport player.cpp /^int rport = 23412;$/;" v
rport referee.cpp /^static int rport[2] = {DEFAULT_DOMAIN_PORT, DEFAULT_DOMAIN_PORT + DEFAULT_DOMAIN_DIFF};$/;" v file:
rport start.cpp /^static int rport = DEFAULT_DOMAIN_PORT;$/;" v file:
run network.cpp /^int NetworkLoop::run()$/;" f class:NetworkLoop
save eval.cpp /^void EvalScheme::save(char* file)$/;" f class:EvalScheme
searchBestMove search-abid.cpp /^void ABIDStrategy::searchBestMove()$/;" f class:ABIDStrategy
searchBestMove search-minimax.cpp /^void MinimaxStrategy::searchBestMove()$/;" f class:MinimaxStrategy
searchBestMove search-onelevel.cpp /^void OneLevelStrategy::searchBestMove()$/;" f class:OneLevelStrategy
searchBestMove search-parallel-abid.cpp /^void ABIDStrategy::searchBestMove()$/;" f class:ABIDStrategy
searchBestMove search-parallel-minimax.cpp /^void MinimaxStrategy::searchBestMove()$/;" f class:MinimaxStrategy
searchStrategies search.cpp /^static SearchStrategy* searchStrategies = 0;$/;" v file:
secsToPlay referee.cpp /^static int secsToPlay = 0;$/;" v file:
secsToPlay start.cpp /^static int secsToPlay = -1;$/;" v file:
seed board.h /^ int seed;$/;" m class:Board
sendBoard player.cpp /^void MyDomain::sendBoard()$/;" f class:MyDomain
sendBoard referee.cpp /^void MyDomain::sendBoard()$/;" f class:MyDomain
sendBoard start.cpp /^void MyDomain::sendBoard()$/;" f class:MyDomain
sendString network.cpp /^bool Connection::sendString(const char* str, int len)$/;" f class:Connection
set network.cpp /^void NetworkTimer::set(struct timeval* tv)$/;" f class:NetworkTimer
setActColor board.h /^ void setActColor(int c) { color=c; }$/;" f class:Board
setBoard eval.cpp /^void Evaluator::setBoard(Board* b)$/;" f class:Evaluator
setColor1Count board.h /^ void setColor1Count(int c) { color1Count = c; }$/;" f class:Board
setColor2Count board.h /^ void setColor2Count(int c) { color2Count = c; }$/;" f class:Board
setDefaults eval.cpp /^void EvalScheme::setDefaults()$/;" f class:EvalScheme
setDepth board.cpp /^void Board::setDepth(int d)$/;" f class:Board
setEvalScheme eval.cpp /^void Evaluator::setEvalScheme(EvalScheme* scheme)$/;" f class:Evaluator
setEvaluator board.h /^ void setEvaluator(Evaluator* ev) { _ev = ev; }$/;" f class:Board
setEvaluator search.h /^ void setEvaluator(Evaluator* e) { _ev = e; }$/;" f class:SearchStrategy
setField board.h /^ void setField(int i, int v) { field[i] = v; }$/;" f class:Board
setFieldValues eval.cpp /^void Evaluator::setFieldValues()$/;" f class:Evaluator
setHost network.cpp /^void Connection::setHost(const char* h)$/;" f class:Connection
setInARowValue eval.cpp /^void EvalScheme::setInARowValue(int stones, int value)$/;" f class:EvalScheme
setMSecsToPlay board.h /^ void setMSecsToPlay(int c, int s) { _msecsToPlay[c] = s; }$/;" f class:Board
setMaxDepth move.h /^ void setMaxDepth(int d)$/;" f class:Variation
setMaxDepth search.h /^ void setMaxDepth(int d) { _maxDepth = d; }$/;" f class:SearchStrategy
setMoveNo board.h /^ void setMoveNo(int n) { _moveNo = n; }$/;" f class:Board
setMoveValue eval.cpp /^void EvalScheme::setMoveValue(int type, int value)$/;" f class:EvalScheme
setRingDiff eval.cpp /^void EvalScheme::setRingDiff(int ring, int value)$/;" f class:EvalScheme
setRingValue eval.cpp /^void EvalScheme::setRingValue(int ring, int value)$/;" f class:EvalScheme
setSearchStrategy board.cpp /^void Board::setSearchStrategy(SearchStrategy* ss)$/;" f class:Board
setSpyLevel board.cpp /^void Board::setSpyLevel(int level)$/;" f class:Board
setState board.cpp /^bool Board::setState(char* s)$/;" f class:Board
setStoneValue eval.cpp /^void EvalScheme::setStoneValue(int stoneDiff, int value)$/;" f class:EvalScheme
setVerbose board.h /^ void setVerbose(int v) { _verbose = v; }$/;" f class:Board
show board.h /^ bool show, bUpdateSpy;$/;" m class:Board
sin network.h /^ struct sockaddr_in sin;$/;" m class:Connection typeref:struct:Connection::sockaddr_in
spyDepth board.h /^ int spyLevel, spyDepth;$/;" m class:Board
spyLevel board.h /^ int spyLevel, spyDepth;$/;" m class:Board
start network.cpp /^bool Connection::start()$/;" f class:Connection
start search.cpp /^void SearchCallbacks::start(int msecsForSearch)$/;" f class:SearchCallbacks
start start.cpp /^static bool start = true;$/;" v file:
start1 move.h /^ enum { all , start1, start2, start3 };$/;" e enum:MoveList::__anon9
start2 move.h /^ enum { all , start1, start2, start3 };$/;" e enum:MoveList::__anon9
start3 move.h /^ enum { all , start1, start2, start3 };$/;" e enum:MoveList::__anon9
startBoard board.cpp /^int Board::startBoard[]={$/;" m class:Board file:
startBoard board.h /^ static int startBoard[AllFields];$/;" m class:Board
startListening network.cpp /^int NetworkDomain::startListening(NetworkLoop* l)$/;" f class:NetworkDomain
startedNode search.cpp /^void SearchCallbacks::startedNode(int d, char* s)$/;" f class:SearchCallbacks
stateDescription board.cpp /^char* Board::stateDescription(int s)$/;" f class:Board
stoneValue eval.h /^ int stoneValue(int s) { return (s>0 && s<6) ? _stoneValue[s] : 0; }$/;" f class:EvalScheme
stopSearch board.cpp /^void Board::stopSearch()$/;" f class:Board
stopSearch search.h /^ void stopSearch() { _stopSearch = true; }$/;" f class:SearchStrategy
storedFirst board.h /^ int storedFirst, storedLast; \/* stored in ring puffer manner *\/$/;" m class:Board
storedLast board.h /^ int storedFirst, storedLast; \/* stored in ring puffer manner *\/$/;" m class:Board
storedMove board.h /^ Move storedMove[MvsStored]; \/* stored moves *\/$/;" m class:Board
strategies search.cpp /^char** SearchStrategy::strategies()$/;" f class:SearchStrategy
strategyNo player.cpp /^int strategyNo = 0;$/;" v
subLeft network.cpp /^bool NetworkTimer::subLeft(struct timeval* tv)$/;" f class:NetworkTimer
subTimeval network.cpp /^void subTimeval(struct timeval* tv1, struct timeval* tv2)$/;" f
substart search.cpp /^void SearchCallbacks::substart(char* s)$/;" f class:SearchCallbacks
t1 referee.cpp /^static struct timeval t1;$/;" v typeref:struct:timeval file:
t1 search.cpp /^static struct timeval t1, t2;$/;" v typeref:struct:timeval file:
t2 search.cpp /^static struct timeval t1, t2;$/;" v typeref:struct: file:
takeBack board.cpp /^bool Board::takeBack()$/;" f class:Board
takeBack search.cpp /^bool SearchStrategy::takeBack()$/;" f class:SearchStrategy
thread_rank player.cpp /^int thread_rank;$/;" v
timeout network.cpp /^void NetworkTimer::timeout(NetworkLoop*)$/;" f class:NetworkTimer
timeout1 board.h /^ timeout1, \/\/ time out for color1 -> win for color2$/;" e enum:Board::__anon3
timeout2 board.h /^ timeout2, \/\/ time out for color2 -> win for color1$/;" e enum:Board::__anon3
timerList network.h /^ NetworkTimer* timerList;$/;" m class:NetworkLoop
type move.h /^ MoveType type;$/;" m class:Move
typeCount move.h /^ enum { typeCount = none,$/;" e enum:Move::__anon7
typeName move.cpp /^char* Move::typeName() const$/;" f class:Move
unlikely search-minimax.cpp 16;" d file:
unlikely search-parallel-minimax.cpp 18;" d file:
update move.cpp /^void Variation::update(int d, Move& m)$/;" f class:Variation
updateSpy board.h /^ void updateSpy(bool b) { bUpdateSpy = b; }$/;" f class:Board
valid1 board.h /^ valid1, \/\/ valid state with color1 to draw$/;" e enum:Board::__anon3
valid2 board.h /^ valid2, \/\/ valid state with color2 to draw$/;" e enum:Board::__anon3
validState board.cpp /^int Board::validState()$/;" f class:Board
verbose network.cpp /^int verbose = 0;$/;" v
verbose search.h /^ int verbose() { return _verbose; }$/;" f class:SearchCallbacks
win1 board.h /^ win1, \/\/ color1 won$/;" e enum:Board::__anon3
win2 board.h /^ win2, \/\/ color2 won$/;" e enum:Board::__anon3
~Board board.h /^ ~Board() {};$/;" f class:Board
~Connection network.cpp /^Connection::~Connection()$/;" f class:Connection
~EvalScheme eval.h /^ ~EvalScheme() {}$/;" f class:EvalScheme
~NetworkDomain network.cpp /^NetworkDomain::~NetworkDomain()$/;" f class:NetworkDomain
~NetworkTimer network.h /^ virtual ~NetworkTimer() {}$/;" f class:NetworkTimer
~SearchCallbacks search.h /^ virtual ~SearchCallbacks() {}$/;" f class:SearchCallbacks
~SearchStrategy search.h /^ virtual ~SearchStrategy() {};$/;" f class:SearchStrategy
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment