home *** CD-ROM | disk | FTP | other *** search
- #define BOARD_C
- #include "Board.h"
- #undef BOARD_C
-
- #pragma segment More
-
- static Board gBoard[kBoardSaved];
-
- // gBoard[0] = current board
- // gBoard[1] = board before last move
- // etc.
-
-
-
-
- short
- AutoPlay (void)
- {
- MoveData move;
- short value;
- short player = gTheGame.CurrentPlayer;
- short strat = gSet.Strategy[player];
- short level = gTheGame.CurrentMove > gStrategies[strat].FastOpen
- ? gSet.Level[player]
- : 0;
-
-
- if (gSet.PlayerKind[player] != macPlayer || gInterrupted)
- return empty;
-
- gMoveStartTicks = TickCount();
-
- switch (gStrategies[strat].Type)
- {
- case boardMiniMax:
-
- gCurrentValue = (*(gStrategies[strat].JudgeProc.boardProc)) (& gBoard[0], player);
-
- // gCurrentValue can be used to measure the progress made.
-
- value = FindBestBoard ( & gBoard[0],
- gStrategies[strat].JudgeProc.boardProc,
- player,
- move,
- level,
- gStrategies[strat].PruneProc,
- kMinJudgeVal,
- kMaxJudgeVal
- );
- break;
-
- case boardMiniMaxNoFliche:
-
- gCurrentValue = (*(gStrategies[strat].JudgeProc.boardProc)) (& gBoard[0], player);
-
- // gCurrentValue can be used to measure the progress made.
-
- value = FindGoodBoard ( & gBoard[0],
- gStrategies[strat].JudgeProc.boardProc,
- player,
- move,
- level,
- gStrategies[strat].PruneProc,
- kMinJudgeVal,
- kMaxJudgeVal
- );
- break;
-
- case boardMiniMaxGreedy:
-
- gCurrentValue = (*(gStrategies[strat].JudgeProc.boardProc)) (& gBoard[0], player);
-
- // gCurrentValue can be used to measure the progress made.
-
- value = FindNiceBoard ( & gBoard[0],
- gStrategies[strat].JudgeProc.boardProc,
- player,
- move,
- level
- );
- break;
-
- case moveMiniMax:
-
- value = FindBestMove ( & gBoard[0],
- gStrategies[strat].JudgeProc.moveProc,
- player,
- move,
- level,
- kMinJudgeVal,
- kMaxJudgeVal
- );
- break;
- default:
- Assert (0, UNKNOWN_SEARCH_METHOD);
- }
-
- if (gInterrupted)
- return empty; // Ignore the thoughts about the last move.
-
- ProcessMove (move, ! gSet.Balls3D);
-
- // The broadcast is done after the board has been modified:
- // The move is still valid, so we can first send just the move,
- // but if sending the move somehow fails,
- // The whole board is already updated and can be sent 'as is'.
-
- BroadcastMove (move, PriorPlayer (CurrentPlayer()), CheckSum (RecentBoard()));
-
- return EndOfGame();
- }
-
-
-
- BoardPtr
- CurrentBoard (void)
- {
- return & gBoard[0];
- }
-
-
-
- BoardPtr
- RecentBoard (void)
- {
- return & gBoard[1];
- }
-
-
-
- Boolean
- FieldHasCurrentPlayersBall (Field f)
- {
- if (f <= 0 || f > kFields)
- return 0;
-
- return gBoard[0].field[f] == gTheGame.CurrentPlayer;
- }
-
-
-
- char
- FieldOwner (Field f)
- {
- return gBoard[0].field[f];
- }
-
-
-
- void
- InitBoard (void)
- {
- short b;
-
- for (b = 0; b < kBoardSaved; b++)
- ResetBoard (& gBoard[b]);
-
- SetPort (gAbaloneWindow);
- SetWRefCon (gAbaloneWindow, (long) (& gBoard[0]));
- InvalBoard();
- }
-
-
-
- static short stackSize = 0;
-
-
- short
- BoardsOnStack (void)
- {
- return stackSize;
- }
-
-
-
- void
- PushBoard (BoardPtr newBoard)
- {
- short b;
-
- for (b = kBoardSaved - 1; --b >= 0; )
- CopyBoard (& gBoard[b], & gBoard[b+1]);
-
- CopyBoard (newBoard, & gBoard[0]);
-
- if (stackSize < kBoardSaved) stackSize++;
- }
-
-
-
- Boolean
- PopBoard (void)
- {
- short b;
-
- if (stackSize <= 0)
- return 0;
-
- for (b = 0; b < kBoardSaved - 1; b++)
- CopyBoard (& gBoard[b+1], & gBoard[b]);
-
- --stackSize;
-
- return 1;
- }
-
-
- void
- CopyBoard (BoardPtr from, BoardPtr to)
- {
- #ifdef THINK_C
- asm
- {
- movea.l from, a0
- movea.l to, a1
-
- moveq #20, d0
-
- @1 move.l (a0)+, (a1)+
- dbra d0, @1
- }
- #elif defined(powerc)
- memcpy (to, from, sizeof (Board));
- #else
-
- // I could do this with the better-looking
- // memcpy (to, from, sizeof (Board));
- // the following doesn't look as nice,
- // but you should take a look at the beautiful compiled code it produces...
-
- register long *b1 = (long *) from;
- register long *b2 = (long *) to;
-
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- *b2++ = *b1++;
- #endif
- }
-
-
-
- Boolean
- EqualBoards (BoardPtr b1, BoardPtr b2)
- {
- return memcmp (& b1->field[1], & b2->field[1], kFields) == 0;
- }
-
-
-
- short
- EndOfGame (void)
- {
- short p;
-
- for (p = 1; p <= gTheGame.Players; p++)
- if (gBoard[0].loot[p-1][0] >= 6)
- return p;
-
- return 0;
- }
-
-
- // The official rules of Abalone don't include a KO rule.
- // For the University of Waterloo contest, it has been added to Abalone to avoid
- // an excessive number of games ending in a draw by endless repetition.
- // The KO rule sais, no board may ever repeat.
- // This means, at least theoretically, that in the search for the best board,
- // EVERY possible board should be compared against every board that has ever been.
- // Without special tricks (using hash functions might be a solution),
- // this would seriously degrade the performance of searching.
- // Therefore, I have chosen to follow the KO rule only partially.
- // To avoid serious performance degradation, ONLY the board resulting from
- // the top-level move under investigation is checked.
- //
- // This is not illegal, and not directly to our advantage either:
- // we only assume our opponent is able to make some extra moves it cannot really make,
- // making it ourselves a bit more difficult to predict his replies.
- //
- // I DO cheat in a different way, however, since I don't compare the resulting
- // board against ALL gone boards, but only against the last kBoardSaved boards.
- // This should not really be a problem, since the probability of a board repeating
- // after a large number of moves has been made is extremely small,
- // even if the players are computers.
-
- Boolean
- MoveIsKO (MovePtr move, short level, short player)
- {
- Board testBoard;
-
- if (player != gTheGame.CurrentPlayer)
-
- // of course, The Enemy can also be in a KO postition, but we're not going into that now.
- // This test has just been added to allow us to play by the rules, nothing more.
-
- return false;
-
- if (level != gSet.Level[player])
-
- // Since we're only testing the legality,
- // we just have to deal with a move that would be made immediately.
-
- return false;
-
- // This is a move that needs some further investigation,
- // since it may result in a direct KO position.
-
- CopyBoard (& gBoard[0], & testBoard);
- if (move[1] == 0)
- DoMove (& testBoard, move);
- else
- DoFlicheMove (& testBoard, move);
-
- return BoardIsKO (& testBoard);
- }
-
-
-
- Boolean
- BoardIsKO (BoardPtr testBoard)
- {
- short b;
-
- for (b = 1; b < kBoardSaved; b++)
- if (EqualBoards (& gBoard[b], testBoard))
- return true;
-
- return false;
- }
-
-
-
- Boolean
- ProcessMove (MovePtr move, Boolean animate)
- {
- BoardPtr board = (BoardPtr) GetWRefCon (gAbaloneWindow);
-
- if (move[0] == 0 || move[3] == down)
- return false;
-
- if (move[1] == 0 && ! ValidMove (board, move))
- return false;
-
- if (move[1] != 0 && ! ValidFlicheMove (board, move))
- return false;
-
- ShowNotation (move, board);
- PushBoard (board);
-
- *((long *) & gLastMove) = *((long *) move);
-
- if (move[1] == 0) // straight move
- {
- ShowMove (move, animate);
-
- if (gSet.SoundOn)
- SndPlayMove (board, move, move[3]);
-
- if (DoMove (board, move) == ball_down)
- {
- if (gSet.SoundOn)
- SndPlayBallDown();
-
- InvalItems (gAbaloneWindow);
- }
- }
- else // fliche move
- {
- ShowFlicheMove (move, animate);
-
- if (gSet.SoundOn)
- SndPlayFlicheMove (board, move, move[3]);
-
- DoFlicheMove (board, move);
- }
-
- gTheGame.CurrentPlayer = NextPlayer (gTheGame.CurrentPlayer);
- gTheGame.CurrentMove++;
- gFileSaved = false;
- UpdateBoard (gAbaloneWindow);
-
- return true;
- }
-
-
-
- unsigned long
- CheckSum (BoardPtr board)
- {
- unsigned long sum = 0L;
- unsigned char *fp = (unsigned char *) board;
- short i;
-
- for (i = 0; i < 32; i++, fp += 2)
- if (*fp) sum += (1L << i);
-
- return sum;
- }
-