public static void Main(string[] args) { Board b = new Board (); Player player1 = null; foreach (var a in args) { if (a.Contains("human")) player1 = new HumanPlayer(b); } if (player1 == null) player1 = new AI(b, 10000); Player player2 = new AI(b, 10000); Player currentPlayer = player1; while (true) { b.PrintBoard(); Move m = currentPlayer.GetMove(); if (m == null) break; m.Apply(b); b.currentColor = (b.currentColor == Color.White ? Color.Black : Color.White); currentPlayer = (currentPlayer == player1 ? player2 : player1); } }
/// <summary> /// Calculates the hash. /// </summary> /// <returns>The hash.</returns> public ulong CalculateHash(Board brd) { ulong hash = 0; for (int i = 0; i < 50; i++) if (brd.pieces1D[i].color != Color.None) hash ^= (ulong)AI.zobristPieceMask[i, brd.pieces1D[i].HashCode]; if (brd.currentColor == Color.Black) hash ^= AI.zobristColorMask; return hash; }
public override ulong Apply(Board b, ulong hash = 0) { #if CHECK_APPLY_UNDO for (int q = 0; q < 10; q++) for (int j = 0; j < 10; j++) if (b.pieces[q,j] != null) pieces2[q,j] = new Piece(q,j,b.pieces[q,j].color, b.pieces[q,j].type); #endif typePriorToApply = b.pieces [x, y].type; int len = hops.Count; // remove origin hash ^= AI.zobristPieceMask[b.pieces[x, y].squareNumIndex, b.pieces [x, y].HashCode]; // update origin and destination // required to do in steps for the case when begin == end Color c = b.pieces [x, y].color; b.pieces [x, y].color = Color.None; // dont care what the type is if it in not occupied b.pieces [hops [len - 1].targetX, hops [len - 1].targetY].color = c; b.pieces [hops [len - 1].targetX, hops [len - 1].targetY].type = typePriorToApply; // Promotion: if (hops [len - 1].targetY == (c == Color.White ? 9 : 0)) b.pieces [hops [len - 1].targetX, hops [len - 1].targetY].type = Piece.Type.Dam; // add destination hash ^= AI.zobristPieceMask[b.pieces[hops [len - 1].targetX, hops [len - 1].targetY].squareNumIndex, b.pieces [hops [len - 1].targetX, hops [len - 1].targetY].HashCode]; // remove victims for (int i = 0; i < len; i++) { #if DEBUG if (b.pieces [hops [i].victimX, hops [i].victimY].color == Color.None) throw new Exception(); #endif hash ^= AI.zobristPieceMask[b.pieces[hops [i].victimX, hops [i].victimY].squareNumIndex, b.pieces [hops [i].victimX, hops [i].victimY].HashCode]; b.pieces [hops [i].victimX, hops [i].victimY].color = Color.None; } #if CHECK_APPLY_UNDO for (int q = 0; q < 10; q++) for (int j = 0; j < 10; j++) if (b.pieces[q,j] != null) pieces4[q,j] = new Piece(q, j, b.pieces[q,j].color, b.pieces[q,j].type); #endif return hash; }
public AI(Board b, int time) { this.b = b; this.time = time; Random rand = new Random(); if (zobristPieceMask == null) { zobristPieceMask = new ulong[50, 4]; for (int i = 0; i < 50; i++) for (int j = 0; j < 4; j++) zobristPieceMask[i,j] = ((ulong)rand.Next()) << 32 | (ulong)rand.Next(); zobristColorMask = ((ulong)rand.Next()) << 32 | (ulong)rand.Next(); } ClearHashes(); }
public HumanPlayer(Board b) { this.b = b; }
public bool GetAllMoves(Board b, MoveSet moveset, TakingMove tm = null, int depth = 0, bool needClone = false) { if (color == Color.None) return false; bool childNeedsClone = false; bool foundNewMove = false; //int direction = color == Color.White ? 1 : -1; int maxSteps = type == Type.Dam ? 10 : 1; for (int yDirection = -1; yDirection <= 1; yDirection += 2) { for (int xDirection = -1; xDirection <= 1; xDirection += 2) { for (int i = 1; i < maxSteps+1; i++) { int targetX = x + i * xDirection; int targetY = y + i * yDirection; if (targetX < 0 || targetX > 9 || targetY < 0 || targetY > 9) break; if (b.pieces [targetX, targetY].color == this.color) { // a piece of our own army break; } else if (b.pieces [targetX, targetY].color == Color.None) { // normal move, need to check y direction if ((type == Type.Dam || (yDirection == (color == Color.White ? 1 : -1))) && tm == null && moveset.minScore == 0) { moveset.moves.Add (new Move(x, y, targetX, targetY)); // normal move, not taking anything } } else // pieces of of opponent { if (b.pieces[targetX, targetY].taken || b.pieces[targetX, targetY] == this || targetX +xDirection < 0 || targetX + xDirection > 9 || targetY + yDirection < 0 || targetY + yDirection > 9) break; if (b.pieces [x + (i+1) * xDirection, y + (i+1) * yDirection].color != Color.None) break; foundNewMove = true; // we can take it! Color c = this.color; this.color = Color.None; int victimX = targetX; int victimY = targetY; bool z = b.pieces[victimX, victimY].taken; // mark it as taken so we cantb.pieces[victimX, victimY].taken jump over it again b.pieces[victimX, victimY].taken = true; // We need to find moves depth-first, or our taken scheme will not work do { targetX += xDirection; targetY += yDirection; if (targetX < 0 || targetX > 9 || targetY < 0 || targetY > 9 || b.pieces [targetX,targetY].color != Color.None) break; if (tm == null) { tm = new TakingMove(x, y); } else if (needClone) { tm = tm.Clone(depth); } #if DEBUG if (b.pieces[victimX,victimY].color == Color.None) throw new Exception(); #endif tm.AddHop(targetX,targetY, victimX, victimY, b.pieces [victimX, victimY].type); b.pieces [targetX,targetY].color = c; //TODO: type!!! b.pieces[targetX, targetY].type = type; childNeedsClone |= b.pieces [targetX,targetY].GetAllMoves(b, moveset, tm, depth + 1, childNeedsClone); b.pieces [targetX,targetY].color = Color.None; needClone = true; } while (++i < maxSteps); #if DEBUG if (b.pieces[victimX, victimY].taken == false) throw new Exception(); #endif b.pieces[victimX, victimY].taken = false; this.color = c; } } } } if (!foundNewMove && tm != null && tm.numTaken >= moveset.minScore) { moveset.moves.Add(tm); moveset.minScore = tm.numTaken; } return foundNewMove; }
public virtual void Undo(Board b, ulong hash = 0) { b.pieces [x, y].color = b.pieces [targetX, targetY].color; b.pieces [x, y].type = typePriorToApply; b.pieces [targetX, targetY].color = Color.None; }
public virtual ulong Apply(Board b, ulong hash = 0) { typePriorToApply = b.pieces [x, y].type; b.pieces [targetX, targetY].color = b.pieces [x, y].color; b.pieces [targetX, targetY].type = b.pieces [x, y].type; if (targetY == (b.pieces [targetX, targetY].color == Color.White ? 9 : 0)) b.pieces [targetX, targetY].type = Piece.Type.Dam; // update hash hash ^= AI.zobristPieceMask[ToHumanReadablePos(x, y) - 1, b.pieces [x, y].HashCode]; hash ^= AI.zobristPieceMask[ToHumanReadablePos(targetX, targetY) - 1, b.pieces [targetX, targetY].HashCode]; b.pieces [x, y].color = Color.None; return hash; }
/// <summary> /// Undo the move /// </summary> /// <param name="b">the board.</param> /// <param name="hash">Hash.</param> public override void Undo(Board b, ulong hash = 0) { #if CHECK_APPLY_UNDO Piece[,] pieces3 = new Piece[10,10]; for (int q = 0; q < 10; q++) for (int j = 0; j < 10; j++) if (b.pieces[q,j] != null) pieces3[q,j] = new Piece(q, j, b.pieces[q,j].color, b.pieces[q,j].type); for (int q = 0; q < 10; q++) for (int j = 0; j < 10; j++) if (b.pieces [q, j] != null) if (pieces4 [q, j].color != b.pieces [q, j].color || (pieces4 [q, j].color != Color.None && b.pieces [q, j].type != pieces4 [q, j].type)) { b.PrintBoard(); int qewqwe = 5; } #endif int len = hops.Count; // required to do in steps for the case when begin == end Color c = b.pieces [hops [len - 1].targetX, hops [len - 1].targetY].color; b.pieces [hops [len - 1].targetX, hops [len - 1].targetY].color = Color.None; b.pieces [x, y].color = c; b.pieces [x, y].type = typePriorToApply; Color victimColor = (c == Color.Black ? Color.White : Color.Black); for (int i = 0; i < len; i++) { b.pieces [hops [i].victimX, hops [i].victimY].color = victimColor; b.pieces [hops [i].victimX, hops [i].victimY].type = hops[i].victimType; } #if CHECK_APPLY_UNDO for (int q = 0; q < 10; q++) for (int j = 0; j < 10; j++) if (b.pieces [q, j] != null) if (pieces2 [q, j].color != b.pieces [q, j].color || (pieces2 [q, j].color != Color.None && b.pieces [q, j].type != pieces2 [q, j].type)) { b.PrintBoard(); int qewqwe = 5; } #endif }