public ulong Reverse(int x, int y, Stone.ColorType color) { var mask = 0x8000000000000000; var move = mask >> (x + y * 8); return(Reverse(move, color)); }
//浅い探索を行いソートした合法手を得る private List <ulong> GetSortedMovailable(Stone.ColorType color, float alpha, float beta) { sortedMoves.Clear(); var movable = board.GetMovableBitBoard(color); while (movable != 0) { var next = GetLeastSignificantBit(movable); board.Log(); board.Reverse(next, color); var eval = -NegaAlpha(Stone.GetReverseColor(color), 1, -beta, -alpha); board.Undo(); sortedMoves.Add(next, eval); movable ^= next; } return(sortedMoves.OrderByDescending(s => s.Value).Select(x => x.Key).ToList <ulong>()); }
public void Move(int x, int y, Stone.ColorType color) { var mask = 0x8000000000000000; var move = mask >> x + y * 8; bitBoards[(int)color] |= move; }
//合法手を描画 public void RenderMarks(List <Vector2Int> movable, Stone.ColorType color) { marks.ForEach(m => Destroy(m.gameObject)); marks.Clear(); RenderMovableMarks(movable, color); }
public ulong Reverse(ulong move, Stone.ColorType color) { int c = (int)color; var opponent = bitBoards[c ^ 1]; ulong allReversed = 0; ulong lineReversed; //一方向ずつ反転できる石を探し重ね合わせる for (var i = 0; i < 8; i++) { var next = ShiftBitboard(move, i); lineReversed = 0; while (next != 0 && (next & opponent) != 0) { lineReversed |= next; next = ShiftBitboard(next, i); } if ((next & bitBoards[c]) != 0) { allReversed |= lineReversed; } } //石を置き、反転させる。 bitBoards[c] |= move | allReversed; bitBoards[c ^ 1] ^= allReversed; return(allReversed); }
public static float Evaluate(LogicBoard logicBoard, Stone.ColorType corrent) { board = logicBoard; var currentBit = board.CurrentBitBoards[(int)corrent]; int currentMovable = CountMovableCells(corrent); EdgeEvaluator.Setup(currentBit); int currentStable = EdgeEvaluator.CountStableStone(currentBit); int currentCMove = EdgeEvaluator.CountCMove(currentBit); int currentXMove = EdgeEvaluator.CountXMove(currentBit); var opponentColor = Stone.GetReverseColor(corrent); var opponentBit = board.CurrentBitBoards[(int)opponentColor]; int opponentMovable = CountMovableCells(opponentColor); EdgeEvaluator.Setup(opponentBit); int opponentStable = EdgeEvaluator.CountStableStone(opponentBit); int opponentCMove = EdgeEvaluator.CountCMove(opponentBit); int opponentXMove = EdgeEvaluator.CountXMove(opponentBit); float eval = (currentMovable - opponentMovable) * mobilityWeight + (currentStable - opponentStable) * stableWeight + (currentCMove - opponentCMove) * cMoveWeight + (currentXMove - opponentXMove) * xMoveWeight; return(eval); }
private void RenderMovableMarks(List <Vector2Int> points, Stone.ColorType color) { points.ForEach(p => { var cell = GetCell(p); var mark = cell.CreateMark(color); marks.Add(mark); }); }
//全てを描画 public void RenderAll(List <Vector2Int> blacks, List <Vector2Int> whites, List <Vector2Int> movable, Stone.ColorType color) { Clear(); blacks.ForEach(p => RenderOne(p, Stone.ColorType.Black)); whites.ForEach(p => RenderOne(p, Stone.ColorType.White)); RenderMovableMarks(movable, color); if (lastMoved != null) { Destroy(lastMoved.gameObject); } }
//最善手を探す public Vector2Int Search(LogicBoard logicBoard, Stone.ColorType color) { board = logicBoard; ulong found = 0; var maxEval = Mathf.NegativeInfinity; var beta = Mathf.Infinity; var a = Mathf.NegativeInfinity; var b = beta; var movables = GetSortedMovailable(color, a, b); if (movables.Count == 1) { return(LogicBoard.BitToPoints(movables[0])[0]); } for (int i = 0; i < movables.Count; i++) { var p = movables[i]; board.Log(); board.Reverse(p, color); var eval = -NegaScout(Stone.GetReverseColor(color), depth - 1, -b, -a); //最初の子ノードは再探索しない(ソートがうまくいっていれば評価が最大だから?) //葉から2つ以内のノードは再探索しない(なぜ?) if (i != 0 && depth > 2 && eval > a && eval < beta) { eval = -NegaScout(Stone.GetReverseColor(color), depth - 1, -beta, -eval); } board.Undo(); if (maxEval < eval) { a = Mathf.Max(a, eval); maxEval = eval; found = p; } b = a + 1; } return(LogicBoard.BitToPoints(found)[0]); }
//NegaAlpha法 private float NegaAlpha(Stone.ColorType color, int depth, float alpha, float beta) { if (depth == 0) { return(Evaluator.Evaluate(board, color)); } var movable = board.GetMovableBitBoard(color); if (LogicBoard.CountBit(movable) == 0) { board.Log(); var eval = -NegaAlpha(Stone.GetReverseColor(color), depth - 1, -beta, -alpha); board.Undo(); return(eval); } while (movable != 0) { ulong next = GetLeastSignificantBit(movable); board.Log(); board.Reverse(next, color); var eval = -NegaAlpha(Stone.GetReverseColor(color), depth - 1, -beta, -alpha); board.Undo(); if (beta <= eval) { return(eval); } alpha = Mathf.Max(eval, alpha); movable ^= next; } return(alpha); }
private Player CreatePlayer(int n, Stone.ColorType color) { Player p; if (n == 0) { p = new Human(); } else { p = new Computer(n); } p.Color = color; return(p); }
//指した石を描画 public void RenderOne(Vector2Int p, Stone.ColorType color) { var cell = GetCell(p); if (stones.Exists(s => s.X == p.x && s.Y == p.y)) { throw new Exception("duplication"); } var stone = cell.CreateStone(color); stones.Add(stone); //最後の手 if (lastMoved != null) { Destroy(lastMoved.gameObject); } lastMoved = cell.CreateMoved(); }
//合法手を返す public ulong GetMovableBitBoard(Stone.ColorType color) { var current = bitBoards[(int)color]; var opponent = bitBoards[(int)color ^ 1]; //左右のセルを除いた相手の盤の状態 var horizontalWatcher = opponent & 0x7e7e7e7e7e7e7e7e; //上下のセルを除いた相手の盤の状態 var verticalWatcher = opponent & 0x00ffffffffffff00; //上下左右のセルを除いた相手の盤の状態 var allSideWatcher = opponent & 0x007e7e7e7e7e7e00; var empty = ~(current | opponent); //8方向それぞれの合法手を調べ重ね合わせる var movable = GetMovableBitBoardInLine(current, empty, horizontalWatcher, c => c << 1); movable |= GetMovableBitBoardInLine(current, empty, horizontalWatcher, c => c >> 1); movable |= GetMovableBitBoardInLine(current, empty, verticalWatcher, c => c << 8); movable |= GetMovableBitBoardInLine(current, empty, verticalWatcher, c => c >> 8); movable |= GetMovableBitBoardInLine(current, empty, allSideWatcher, c => c << 7); movable |= GetMovableBitBoardInLine(current, empty, allSideWatcher, c => c >> 7); movable |= GetMovableBitBoardInLine(current, empty, allSideWatcher, c => c << 9); movable |= GetMovableBitBoardInLine(current, empty, allSideWatcher, c => c >> 9); return(movable); }
//NegaScout法 private float NegaScout(Stone.ColorType color, int depth, float alpha, float beta) { if (depth == 0) { return(Evaluator.Evaluate(board, color)); } var movables = GetSortedMovailable(color, alpha, beta); if (movables.Count == 0) { board.Log(); var eval = -NegaScout(Stone.GetReverseColor(color), depth - 1, -beta, -alpha); board.Undo(); return(eval); } var maxEval = Mathf.NegativeInfinity; var a = alpha; var b = beta; for (int i = 0; i < movables.Count; i++) { var p = movables[i]; board.Log(); board.Reverse(p, color); var eval = -NegaScout(Stone.GetReverseColor(color), depth - 1, -b, -a); //最初の子ノードは再探索しない(ソートがうまくいっていれば評価が最大だから?) //葉から2つ以内のノードは再探索しない(なぜ?) if (i != 0 && depth > 2 && eval > a && eval < beta) { eval = -NegaScout(Stone.GetReverseColor(color), depth - 1, -beta, -eval); } board.Undo(); if (maxEval < eval) { if (beta <= eval) { return(eval); } a = Mathf.Max(a, eval); maxEval = eval; } b = a + 1; } //子ノードの最大値を返す(fail-soft) return(maxEval); }
//合法手の数を取得 private static int CountMovableCells(Stone.ColorType color) { var movable = board.GetMovableBitBoard(color); return(LogicBoard.CountBit(movable)); }
public void Show(Stone.ColorType color) { image.sprite = passSprites[(int)color]; }