Example #1
0
        public static Board ApplyMove(Board Board, Move Move)
        {
            var checkForSurrounded = new List<Coordinate>();
            var checkForEmpty = new List<byte>();
            var sniping = false;

            switch ((MoveType)Move.Type)
            {
                case MoveType.Trade:
                    {
                        /*
                        // Verify move is legal.

                        // Reject move if attempting to snipe own piece.
                        if (Move.Triangle % 2 != Board.Header.WhoseTurnNext) throw new InvalidOperationException();

                        // Reject move if player does not hold at least two tiles.
                        var heldTileCount = Board.Tiles.Count(t => t.IsHeldBy(Board.Header.WhoseTurnNext));
                        if (heldTileCount < 2) throw new InvalidOperationException();

                        // Reject move if there is no enemy piece at the location.
                        if (Board.GetTriangle(Move.Coordinate) == 0) throw new InvalidOperationException();
                        */
                        // Turn is legal, mutate board.
                        foreach (var tile in Board.Tiles.Where(t => t.IsHeldBy(Board.Header.WhoseTurnNext)).Take(2))
                            Board = Board.WithTile(tile.ID, tile.WithStatus(0x03));
                        Board = Board.WithTile(Move.Tile, Board.GetTile(Move.Tile).WithTriangle(Move.Triangle, 0));

                        checkForEmpty.Add(Move.Tile);
                        sniping = true;
                    }
                    break;
                case MoveType.MovePiece:
                    {
                        /*
                        // Verify move is legal.

                        // Reject move if attempting to move opponent piece.
                        if (Move.Triangle % 2 == Board.Header.WhoseTurnNext) throw new InvalidOperationException();

                        // Reject move if there is no piece at the location.
                        if (Board.GetTriangle(Move.Coordinate) == 0) throw new InvalidOperationException();

                        // Find destination triangle coordinate.
                        */
                        var dest = FindMoveNeighbor(Move.Coordinate, Move.Direction);
                        /*
                        // Reject move if player attempted to move off board.
                        if (dest.Invalid) throw new InvalidOperationException();
                        if (Board.GetTile(dest.Tile).IsOutOfPlay()) throw new InvalidOperationException();

                        // Reject move if destination triangle is occupied.
                        if (Board.GetTriangle(dest) != 0) throw new InvalidOperationException();
                        */
                        // Move is legal, mutate board.

                        Board = Board.WithTile(Move.Tile, Board.GetTile(Move.Tile).WithTriangle(Move.Triangle, 0));
                        Board = Board.WithTile(dest.Tile, Board.GetTile(dest.Tile).WithTriangle(dest.Triangle, 1));

                        checkForEmpty.Add(Move.Tile);

                        for (byte x = 0; x < 3; ++x)
                        {
                            var neighbor = FindSurroundNeighbor(dest, x);
                            if (!neighbor.Invalid && !Board.GetTile(neighbor.Tile).IsOutOfPlay())
                                checkForSurrounded.Add(neighbor);
                        }
                    }
                    break;
            }

            while (checkForSurrounded.Count > 0 || checkForEmpty.Count > 0)
            {
                while (checkForSurrounded.Count > 0)
                {
                    var piece = checkForSurrounded[0];
                    checkForSurrounded.RemoveAt(0);

                    var sum = 0;
                    for (byte x = 0; x < 3; ++x)
                    {
                        var neighbor = FindSurroundNeighbor(piece, x);
                        if (neighbor.Invalid || Board.GetTile(neighbor.Tile).IsOutOfPlay())
                            sum += 1;
                        else
                            sum += Board.GetTriangle(neighbor);
                    }

                    if (sum == 3)
                    {
                        Board = Board.WithTile(piece.Tile, Board.GetTile(piece.Tile).WithTriangle(piece.Triangle, 0));
                        checkForEmpty.Add(piece.Tile);
                    }
                }

                while (checkForEmpty.Count > 0)
                {
                    var tileID = checkForEmpty[0];
                    checkForEmpty.RemoveAt(0);

                    if (!Board.GetTile(tileID).IsEmpty())
                        continue;

                    // Tile is empty - if it has 3 or less adjacent tiles in a row, it can be removed.

                    var runs = new AdjacentRun[3];
                    var runsCount = 0;

                    for (var x = 0; x < 6; ++x)
                    {
                        var neighbor = Tables.TileAdjacency[tileID][x];
                        if (neighbor != 0xFF && !Board.GetTile(neighbor).IsOutOfPlay())
                        {
                            if (runsCount == 0)
                            {
                                runs[0] = new AdjacentRun(x, x, 1);
                                runsCount += 1;
                            }
                            else if (runs[runsCount - 1].End == x - 1)
                                runs[runsCount - 1] = new AdjacentRun(runs[runsCount - 1].Start, x, runs[runsCount - 1].Count + 1);
                            else
                            {
                                runs[runsCount] = new AdjacentRun(x, x, 1);
                                runsCount += 1;
                            }
                        }
                    }

                    if (runsCount > 1 && runs[0].Start == 0 && runs[runsCount - 1].End == 5)
                    {
                        runs[0] = new AdjacentRun(runs[runsCount - 1].Start, runs[0].End, runs[0].Count + runs[runsCount - 1].Count);
                        runsCount -= 1;
                    }

                    if (runsCount == 1 && runs[0].Count <= 3)
                    {
                        if (sniping)
                            Board = Board.WithTile(tileID, Board.GetTile(tileID).WithStatus(0x03));
                        else
                            Board = Board.WithTile(tileID, Board.GetTile(tileID).WithStatus((byte)(Board.Header.WhoseTurnNext + 1)));

                        // Mark adjacent triangles for surround consideration.
                        for (var x = 0; x < 6; ++x)
                        {
                            // Don't check own pieces for surround
                            if (Tables.ExposedAdjacency[x] % 2 != Board.Header.WhoseTurnNext) continue;

                            // Don't check tiles that don't exist.
                            var neighbor = Tables.TileAdjacency[tileID][x];
                            if (neighbor == 0xFF || Board.GetTile(neighbor).IsOutOfPlay()) continue;

                            checkForSurrounded.Add(new Coordinate(neighbor, Tables.ExposedAdjacency[x]));
                        }

                        // Check neighboring tiles to see if they can be removed.
                        for (var x = 0; x < 6; ++x)
                        {
                            var neighbor = Tables.TileAdjacency[tileID][x];
                            if (neighbor == 0xFF || Board.GetTile(neighbor).IsOutOfPlay()) continue;
                            checkForEmpty.Add(neighbor);
                        }
                    }
                }
            }

            if (Board.Header.WhoseTurnNext == 0)
                Board = Board.WithHeader(new StateHeader(0x80));
            else
                Board = Board.WithHeader(new StateHeader(0x00));

            return Board;
        }