static void EnumUnstackMoves(IList <IMove> dest, GameState state, PickupAndPlaceMove template, int start, BoardPosition pos, int dir) { var targetPos = Direction.Offset(pos, dir); if (!state.IsPositionLegal(targetPos)) { return; } var stack = state.Board[targetPos.X, targetPos.Y]; var stacktop = state[targetPos]; bool flatten = false; if (stacktop.HasValue) { var topstone = Piece.GetStone(stacktop.Value); // destination stack must not have cap stone if (topstone == Piece.Stone_Cap) { return; } // only capstone by itself may flatten standing stone if (topstone == Piece.Stone_Standing) { if (template.PickUpMove.PickUpCount - start != 1) { return; } if (!template.PickUpMove.IsCapStone(start)) { return; } flatten = true; } } var pickupMove = template.PickUpMove; int maxPlace = pickupMove.PickUpCount - start; for (int i = 1; i <= maxPlace; i++) { for (int j = 0; j < i; j++) { template.AddToChain(pickupMove.GeneratePlaceFromStack(j + start, targetPos, flatten)); } if (i + start == pickupMove.PickUpCount) { dest.Add(template.ShallowCopy()); } else { EnumUnstackMoves(dest, state, template, start + i, targetPos, dir); } template.RemoveFromEnd(i); } }
/// <summary> /// Enumerate all legal moves in the current board position /// </summary> /// <param name="dest">Destination list into which moves will be added</param> /// <param name="game">Current game state</param> /// <param name="moveOrder">Order in which board positions will be considered</param> public static void EnumerateMoves(IList <IMove> dest, GameState game, IList <BoardPosition> moveOrder) { int player = game.Ply & 1; if (game.Ply < 2) { // place enemy flat stone on empty squares player = player ^ 1; foreach (var pos in moveOrder) { if (!game[pos].HasValue) { dest.Add(new PlacePieceMove(Piece.MakePieceID(Piece.Stone_Flat, player), pos, true, false)); } } } else { // place stones on empty squares var sremain = game.StonesRemaining[player]; var cremain = game.CapRemaining[player]; foreach (var pos in moveOrder) { if (!game[pos].HasValue) { if (sremain > 0) { dest.Add(new PlacePieceMove(Piece.MakePieceID(Piece.Stone_Flat, player), pos, true, false)); dest.Add(new PlacePieceMove(Piece.MakePieceID(Piece.Stone_Standing, player), pos, true, false)); } if (cremain > 0) { dest.Add(new PlacePieceMove(Piece.MakePieceID(Piece.Stone_Cap, player), pos, true, false)); } } } // Move stacks foreach (var pos in moveOrder) { var stack = game.Board[pos.X, pos.Y]; if (stack.Count == 0) { continue; } var topPiece = stack[stack.Count - 1]; var topStone = Piece.GetStone(topPiece); if (Piece.GetPlayerID(topPiece) != player) { continue; } for (int pickupCount = 1; pickupCount <= Math.Min(stack.Count, game.Size); pickupCount++) { var pickupMove = new PickUpMove(pos, pickupCount, game); var template = new PickupAndPlaceMove(pickupMove); for (int dir = 0; dir < 4; dir++) { EnumUnstackMoves(dest, game, template, 0, pos, dir); } } } } }
/// <summary> /// Creates a shallow copy by copying the contained moves into a new list /// </summary> private PickupAndPlaceMove(PickupAndPlaceMove source) : base(source.Moves) { }