home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-09-21 | 10.5 KB | 464 lines | [TEXT/MPS ] |
- //==========================================================================================//
- // //
- // THE COMMENT GIVEN IN THIS FILE SHOULD BE MOST OF WHAT YOU NEED TO ADD A NEW STRATEGY //
- // //
- //==========================================================================================//
-
-
- #define STRATEGIES_C
- #include "Strategies.h"
- #undef STRATEGIES_C
-
-
- #pragma segment More
-
-
- // The easiest way to implement a new strategy is to make a BoardJudgeProc.
- // The function TheFinalStrategy right below is all yours to try this,
- // but first read more about the conventions used in this program right below.
-
-
- short
- TheFinalStrategy (BoardPtr board, short player)
- {
- #if ! defined (__SC__) && ! defined (__MWERKS__)
- #pragma unused(board, player)
- #endif
- // Just pick a random value.
- // This needs some improvement.
-
- return TickCount() % 100;
- }
-
-
-
- // To speed things up, you can optionally use a pruning function.
-
- Boolean
- TheFinalGardener (short level, short value, short best)
- {
- #if ! defined (__SC__) && ! defined (__MWERKS__)
- #pragma unused(level, value, best)
- #endif
- // A random half of the moves is worth a closer look.
-
- return TickCount() % 2; // true means: prune this, not interesting
- }
-
-
-
- /* The conventions used in this program are different from the ones described
- * in the contest announcement. (Sorry, this program was made before the contest.)
- * I'm working on a translation between the contest convention and my own,
- * which is halfway finished (from my convention to the official notation, see contest.h)
- *
- *********************** CONVENTIONS USED IN THIS PROGRAM ********************
- *
- * Fields are numbered from 1 to 61 (field number 0 has a special meaning; don't use it).
- * Numbering starts at the topleft field in this program, first going to the right, then down.
- *
- *
- * 1 2 3 4 5
- *
- *
- * 6 7 8 9 10 11
- *
- *
- * 12 13 14 15 16 17 18
- *
- *
- * 19 20 21 22 23 24 25 26
- *
- *
- * 27 28 29 30 31 32 33 34 35
- *
- *
- * 36 37 38 39 40 41 42 43
- *
- *
- * 44 45 46 47 48 49 50
- *
- *
- * 51 52 53 54 55 56
- *
- *
- * 57 58 59 60 61
- *
- *
- *
- * A BoardJudgeProc gets a BoardPtr and a short as parameters (see file Compute.h);
- * It should return a short value telling how good it thinks a given board is.
- * (A higher value means the board is judged better.)
- * A MoveJudgeProc should return a value telling how much the value of the board
- * has CHANGED because of the given move.
- *
- * The first parameter, the BoardPtr, points to a simple struct (see rules.h):
- *
- * typedef struct _game
- * {
- * Fields field;
- * Loot loot;
- * } Board, *BoardPtr;
- *
- *
- * The field field is an array of 62 unsigned chars, representing the board to be judged.
- * The first element is to be ignored (fields run from 1 to 61, remember?)
- * Each of the 61 fields has the value 0 (empty), 1 (white) or 2 (black).
- *
- * For implementing a strategy, you probably don't need the loot field
- * (the number of balls pushed off is stored here).
- *
- * Directions are numbered clockwise starting from 0 (left) to 5 (topleft) (see rules.h again)
- */
-
- /* OK, you could start programming with this knowledge,
- * but I suggest you take a look at the example given below first.
- */
-
-
- /* This is the table specifying the stragegies appearing in the strategy popup menu.
- * Don't forget to sign in your strategy by filling out a nice name for it.
- * If you don't have a pruning function, you can make it NULL.
- */
-
-
- StrategyStruct gStrategies[] =
- {
- // These are the best strategies I can think of so far
- { boardMiniMaxGreedy, Arnold, NULL, kDefaultFast, "\pTerminator III" },
- { boardMiniMaxNoFliche, Ross, NULL, kDefaultFast, "\pDarth Vader" },
- { moveMiniMax, (BoardJudgeProc) Bill, NULL, kDefaultFast, "\pWilliam Gates IV" },
- { boardMiniMaxGreedy, Frankie, NULL, kDefaultFast, "\pFrankie Kruger" },
-
- // This is for you to improve upon. Add multiple if you like.
-
- #ifdef TRY_THIS
- { boardMiniMaxNoFliche, & TheFinalStrategy, NULL, kDefaultFast, "\pWhat's in a name" },
- #endif
-
-
- // The table should end with a NULL proc, don't remove
-
- { moveMiniMax, NULL, NULL, 0, "\pSentinel" }
- };
-
-
-
- // A PruneJudgeProc.
- // I don't have much success finding really good pruning functions yet.
-
- Boolean
- Sarah (short level, short value, short best)
- {
- #define MAXTICKS 500
-
- if (level == 2)
- {
- // Pruning is always at 2 plies from the default lowest level:
- // one ply for me, and one for the opponent.
- // This way, results from different search depths can safely be compared
-
- return (TickCount() > gMoveStartTicks + MAXTICKS)
- && value < best;
- }
- return false;
- }
-
-
-
- // The following is a slight improvement over the old BoardJudgeProc explained above.
-
- short
- Ross (BoardPtr board, short player)
- {
- static Boolean firstTime = true;
- static short value[kFields+1];
- static unsigned char bestNeighbour[kFields+1][2];
-
- register Field f;
- register unsigned char d;
- register short boardValue = 0;
-
- if (firstTime) // initialise values for all fields
- {
- firstTime = false;
-
- value[0] = 1 << 10;
-
- for (f = 1; f <= kFields; f++)
- {
- short d;
-
- for (value[f] = 0, d = 0; d < 6; d++)
- value[f] += 1 << (10 - Distance (f, d));
-
- value[f] /= 6;
- value[f] = 1024 - value[f];
- }
- for (f = 1; f <= kFields; f++)
- {
- short d, best = 0;
-
- for (d = right; d < down; d++)
- {
- if (value[Neighbour (f, d)] > best)
- {
- best = value[Neighbour (f, d)];
- bestNeighbour[f][0] = Neighbour (f, d);
- }
- }
- }
- for (f = kFields + 1; --f > 0; )
- {
- short d, best = 0;
-
- for (d = right; d < down; d++)
- {
- if (value[Neighbour (f, d)] > best)
- {
- best = value[Neighbour (f, d)];
- bestNeighbour[f][1] = Neighbour (f, d);
- }
- }
- }
- }
-
- for (f = 1; f <= 61; f++)
- {
- if (board->field[f] == player)
- {
- boardValue += value[f];
-
- for (d = right; d < down; d++)
- {
- if ( board->field[f] == board->field[Neighbour (f,d)])
- {
- if (Neighbour (f, d) == bestNeighbour[f][0])
- boardValue += 32;
-
- if (Neighbour (f, d) == bestNeighbour[f][1])
- boardValue += 32;
- }
- }
- }
- else if (board->field[f])
- {
- boardValue -= value[f];
-
- for (d = right; d < down; d++)
- {
- if ( board->field[f] == board->field[Neighbour (f,d)])
- {
- if (Neighbour (f, d) == bestNeighbour[f][0])
- boardValue -= 32;
-
- if (Neighbour (f, d) == bestNeighbour[f][1])
- boardValue -= 32;
- }
- }
- }
- }
- return boardValue;
- }
-
-
-
- // Example of a simple BoardJudgeProc that can be recoded to a MoveJudgeProc.
- // Recoding is simple in this particular case, because only statical values are used.
- // The result of recoding Paul would be Bill; you'll find him below.
-
- short
- Paul (BoardPtr board, short player)
- {
- static Boolean firstTime = true;
- static short value[kFields+1];
-
- Field f;
- short boardValue = 0;
-
- if (firstTime) // initialise values for all fields
- {
- short f;
-
- firstTime = false;
-
- for (f = 1; f <= kFields; f++)
- {
- short d;
-
- for (value[f] = 0, d = 0; d < 6; d++)
- value[f] += 1 << (10 - Distance (f, d));
-
- value[f] /= 6;
- }
- }
-
- // the values have been computed now, and can be used.
-
- for (f = 1; f <= 61; f++)
- {
- if (board->field[f] == player)
-
- boardValue += 1024 - value[f];
-
- else if (board->field[f] != empty)
-
- boardValue -= 1024 - value[f];
- }
- return boardValue;
- }
-
-
-
- // A reasonable MoveJudgeProc. Not as strong as Ross, but faster
-
- short
- Bill (BoardPtr board, short player, MovePtr field)
- {
- static Boolean firstTime = true;
- static short value[kFields+1];
-
- Field f;
- short boardValue = 0;
- short direction = field[3];
-
- if (firstTime) // initialise values for all fields
- {
- firstTime = false;
-
- for (f = 1; f <= kFields; f++)
- {
- short d;
-
- for (value[f] = 0, d = 0; d < 6; d++)
- value[f] += 1 << (10 - Distance (f, d));
-
- value[f] /= 6;
- }
- }
-
- if (field[1] != 0) // fliche move
- {
- for (f = 0; f < 3 && field[f] != 0; f++)
- {
- boardValue += value[field[f]];
- boardValue -= value[Neighbour (field[f], direction)];
- }
- }
- else // normal move
- {
- for (f = field[0]; f != 0 && board->field[f] != empty; f = Neighbour (f, direction))
- {
- if (Neighbour (f, direction) == 0 && board->field[f] != empty)
- boardValue += 1024;
-
- if (board->field[f] == player)
- {
- boardValue += value[f];
- boardValue -= value[Neighbour (f, direction)];
- }
- else
- {
- boardValue += value[Neighbour (f, direction)];
- boardValue -= value[f];
- }
- }
- }
- return boardValue;
- }
-
-
-
- short
- Frankie (BoardPtr board, short player)
- {
- static Boolean firstTime = true;
- static unsigned char dist[kFields+1][kFields+1];
-
- Field f, g;
- long playerSumDist = 0, othersSumDist = 0;
- short n_player = 0, n_others = 0;
- Field playerField[14+1], othersField[14+1];
-
- if (firstTime) // Compute distances between all fields.
- {
- Field h;
- Boolean allDone;
-
- firstTime = false;
-
- for (f = 0; f <= kFields; f++)
- for (g = 0; g <= kFields; g++)
- dist[f][g] = 0;
-
- // Start with all known neighbours.
-
- for (f = 1; f <= kFields; f++)
- for (g = 1; g <= kFields; g++)
- if (f != g && Neighbours (f, g))
- dist[f][g] = dist[g][f] = 1;
-
- // Compute all remaining distances.
-
- do // Until we found a minimal distance for each combination of fields.
- {
- allDone = true;
-
- for (f = 1; f <= kFields; f++)
- {
- for (g = 1; g <= kFields; g++)
- {
- for (h = 1; h <= kFields; h++)
- {
- if (f == g || f == h || g == h)
- continue;
-
- if (dist[f][h] == 0 || dist[h][g] == 0)
- {
- allDone = false;
- continue;
- }
-
- if (dist[f][g] == 0 || dist[f][h] + dist[h][g] < dist[f][g])
- {
- allDone = false;
- dist[f][g] = dist[g][f] = dist[f][h] + dist[h][g];
- }
- }
- }
- }
- }
- while (! allDone);
- }
-
- // Find the fields for this player and for the other(s)
-
- for (f = 1; f <= 61; f++)
- {
- if (board->field[f] == player)
- playerField[n_player] = f, n_player++;
- else if (board->field[f] != empty)
- othersField[n_others] = f, n_others++;
- }
-
- // Now we can iterate over the fields using playerField[] and othersField[]
-
- for (f = 0; f < n_player-1; f++)
- {
- for (g = f+1; g < n_player; g++)
- {
- playerSumDist += dist[playerField[f]][playerField[g]]<<1;
- playerSumDist += dist[playerField[f]][31];
- }
- }
- for (f = 0; f < n_others-1; f++)
- {
- for (g = f+1; g < n_others; g++)
- {
- othersSumDist += dist[othersField[f]][othersField[g]]<<1;
- othersSumDist += dist[othersField[f]][31];
- }
- }
- return (short) (othersSumDist - playerSumDist + (n_player - n_others) * 256);
- }
-