Ejemplo n.º 1
0
        /////////////////////////////////////////////////////////////////
        ////// START: A code for creating all possible permutations of board positions
        ////// of tiles in given list, starting from left-most tile in the array

        private void boardPosPermAddChildNodes(CandidateTileSeq candTileSeq, int currTileIndex, TreeNode parentNode, TileZeroTile[,] tileArray, VirtualBoard virtualBoard)
        {
            if (currTileIndex >= candTileSeq.getTileCount())
            {
                return;
            }

            TileZeroTile tile = candTileSeq.getTileAt(currTileIndex);

            for (int currRowIndex = 0; currRowIndex < tileArray.GetLength(0); currRowIndex++)
            {
                for (int currColIndex = 0; currColIndex < tileArray.GetLength(1); currColIndex++)
                {
                    int resultScore = virtualBoard.isValidMove(currRowIndex, currColIndex, tile, true, tileArray, false);

                    if (resultScore != Cfg.NONE)
                    {
                        TileZeroTile[,] newTileArray = Cfg.createBoardCopy(tileArray);
                        virtualBoard.addTile(currRowIndex, currColIndex, tile, false, newTileArray);
                        TreeNode childNode = parentNode.addChildNodeValue(new AbstractPos(currTileIndex, currRowIndex, currColIndex, resultScore));
                        boardPosPermAddChildNodes(candTileSeq, currTileIndex + 1, childNode, newTileArray, virtualBoard);
                    }
                }
            }

            boardPosPermAddChildNodes(candTileSeq, currTileIndex + 1, parentNode, tileArray, virtualBoard); // [SC][2016.12.08] new code
        }
Ejemplo n.º 2
0
        ////// END: hard ai functionality
        /////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////
        ////// START: very hard ai functionality
        #region very hard AI
        public void invokeVeryHardAI()
        {
            CandidateTilePos selectedPosCombo = calculateMoves(true, true, false);

            if (selectedPosCombo == null)   // [SC] no tiles to put on a board
            // [SC] dropping a random tile
            {
                setSelectedTile(playerTiles.getRandomElement());
                game.dropPlayerTile(playerIndex);
            }
            else if (getCanMove())
            {
                CandidateTileSeq tileSeq = selectedPosCombo.getCandidateTileSeq();
                int totalMoveCount       = selectedPosCombo.getComboLength();
                int currMoveCount        = 0;

                while (currMoveCount < totalMoveCount)
                {
                    AbstractPos abstrPos  = selectedPosCombo.getAbstrPosAt(currMoveCount);
                    int         rowIndex  = abstrPos.getRowIndex();
                    int         colIndex  = abstrPos.getColIndex();
                    int         tileIndex = abstrPos.getTileIndex();

                    TileZeroTile tile = tileSeq.getTileAt(tileIndex);

                    setSelectedTile(tile);

                    game.setSelectedCell(rowIndex, colIndex, playerIndex);

                    game.placePlayerTileOnBoard(playerIndex);

                    currMoveCount++;
                }
            }
        }
Ejemplo n.º 3
0
        // [2016.12.01]
        // [SC] place active player's tile on a board
        public void placePlayerTileOnBoard(int playerIndex)
        {
            if (!activeGameFlag)
            {
                return;
            }

            if (playerIndex != activePlayerIndex)
            {
                Cfg.log("It is not your turn!");
                return;
            }

            Player activePlayer = players[activePlayerIndex];

            // [SC] check if player can put tiles on a board
            if (!activePlayer.getCanMove())
            {
                Cfg.log("Cannot move a tile after dropping a tile!"); // [TODO]
                return;
            }

            // [SC] check if board position is selected
            if (!isSelected())
            {
                Cfg.log("Select a board position at first!"); // [TODO]
                return;
            }

            // [SC] check if player tile is selected
            if (!activePlayer.isTileSelected())
            {
                Cfg.log("Select a tile at first!"); // [TODO]
                return;
            }

            TileZeroTile tile   = activePlayer.getSelectedTile();
            int          result = putTileOnBoard(selectedRowIndex, selectedColIndex, tile, true);

            if (result != Cfg.NONE)
            {
                Cfg.log(String.Format("    Put tile {0} at position {1}-{2} for {3} points.", tile.ToString(), selectedRowIndex, selectedColIndex, result));

                // [SC] increase player's score
                activePlayer.increaseScore(result);

                // [SC] remove the tile from the player and reset player selection
                activePlayer.removeSelectedTile();

                // [SC] disable mismatching tiles
                activePlayer.disableMismatchedTiles(tile.getColorIndex(), tile.getShapeIndex());

                // [SC] prevent the player from dropping tiles in the same turn
                activePlayer.setCanDrop(false);

                // [SC] reset board selection
                resetSelected();
            }
        }
Ejemplo n.º 4
0
        /////////////////////////////////////////////////////////////////
        ////// START: generic functions for manipulating tiles

        public bool addTile(TileZeroTile tile)
        {
            if (getPlayerTileCount() < Cfg.MAX_PLAYER_TILE_COUNT)
            {
                playerTiles.Add(tile);
                return(true);
            }
            return(false);
        }
Ejemplo n.º 5
0
 // [SC] returns true if this tile has the same color and shape as another tile
 public bool sameVisTile(TileZeroTile tile)
 {
     if (this.colorIndex == tile.getColorIndex() && this.shapeIndex == tile.getShapeIndex())
     {
         return(true);
     }
     else
     {
         return(false);
     }
 }
Ejemplo n.º 6
0
        ////// END: A code for creating all possible permutations of board positions
        ////// of tiles in given list, starting from left-most tile in the array
        /////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////
        ////// START: A code for creating all possible permutations of tiles in list

        private void tileListPermAddChildNodes(List <TileZeroTile> tileList, int childValIndex, TreeNode rootNode)
        {
            List <TileZeroTile> newList        = tileList.listShallowClone();
            TileZeroTile        childNodeValue = newList.Pop(childValIndex);
            TreeNode            childNode      = rootNode.addChildNodeValue(childNodeValue);

            for (int tileIndex = 0; tileIndex < newList.Count; tileIndex++)
            {
                tileListPermAddChildNodes(newList, tileIndex, childNode);
            }
        }
Ejemplo n.º 7
0
        public override string ToString()
        {
            string boardStr = "";

            string indexRow = "   ";
            string brRow    = "   ";

            for (int colIndex = 0; colIndex < colCount; colIndex++)
            {
                if (colIndex < 10)
                {
                    indexRow += "0" + colIndex + " ";
                }
                else
                {
                    indexRow += colIndex + " ";
                }

                brRow += "---";
            }
            boardStr += indexRow + "\n";
            boardStr += brRow + "\n";

            for (int rowIndex = 0; rowIndex < rowCount; rowIndex++)
            {
                string rowStr = "";

                if (rowIndex < 10)
                {
                    rowStr += "0" + rowIndex + "|";
                }
                else
                {
                    rowStr += rowIndex + "|";
                }

                for (int colIndex = 0; colIndex < colCount; colIndex++)
                {
                    TileZeroTile tile = tileArray[rowIndex, colIndex];
                    if (tile == null)
                    {
                        rowStr += "-- ";
                    }
                    else
                    {
                        rowStr += tile.ToString() + " ";
                    }
                }
                boardStr += rowStr + "\n";
            }

            return(boardStr);
        }
Ejemplo n.º 8
0
        ////// END: functions for manipulating a selected tile
        /////////////////////////////////////////////////////////////////

        public void disableMismatchedTiles(int colorIndex, int shapeIndex)
        {
            if (!hasColorReq() && !hasShapeReq())
            {
                setColorReq(colorIndex);
                setShapeReq(shapeIndex);
            }
            else if (hasColorReq() && hasShapeReq())
            {
                if (sameColorReq(colorIndex) && !sameShapeReq(shapeIndex))
                {
                    resetShapeReq();
                }
                else if (!sameColorReq(colorIndex) && sameShapeReq(shapeIndex))
                {
                    resetColorReq();
                }
            }

            if (hasColorReq() && hasShapeReq())
            {
                for (int currTileIndex = 0; currTileIndex < playerTiles.Count; currTileIndex++)
                {
                    TileZeroTile tile = playerTiles[currTileIndex];
                    if (!sameColorReq(tile.getColorIndex()) && !sameShapeReq(tile.getShapeIndex()))
                    {
                        tile.setPlayable(false);
                    }
                }
            }
            else if (hasColorReq() && !hasShapeReq())
            {
                for (int currTileIndex = 0; currTileIndex < playerTiles.Count; currTileIndex++)
                {
                    TileZeroTile tile = playerTiles[currTileIndex];
                    if (!sameColorReq(tile.getColorIndex()))
                    {
                        tile.setPlayable(false);
                    }
                }
            }
            else if (!hasColorReq() && hasShapeReq())
            {
                for (int currTileIndex = 0; currTileIndex < playerTiles.Count; currTileIndex++)
                {
                    TileZeroTile tile = playerTiles[currTileIndex];
                    if (!sameShapeReq(tile.getShapeIndex()))
                    {
                        tile.setPlayable(false);
                    }
                }
            }
        }
Ejemplo n.º 9
0
        ////// END: generic functions for manipulating tiles
        /////////////////////////////////////////////////////////////////

        /////////////////////////////////////////////////////////////////
        ////// START: functions for manipulating a selected tile

        private bool setSelectedTile(TileZeroTile tile)
        {
            // [TODO] make sure the tile is one of the player's tiles
            if (!tile.getPlayable())
            {
                Cfg.log(String.Format("The tile {0}{1} is not playable.", tile.getColorIndex(), tile.getShapeIndex()));
            }
            else
            {
                selectedTile = tile;
                return(true);
            }

            return(false);
        }
Ejemplo n.º 10
0
        public int addTile(int rowIndex, int colIndex, TileZeroTile tile, bool validCheck, TileZeroTile[,] tileArrayP)
        {
            if (tileArrayP == null)
            {
                tileArrayP = tileArray;
            }

            int result = isValidMove(rowIndex, colIndex, tile, validCheck, tileArrayP, true);

            if (result != Cfg.NONE)
            {
                tileArrayP[rowIndex, colIndex] = tile;
            }

            return(result);
        }
Ejemplo n.º 11
0
 // [2016.12.01]
 protected void fillPlayerTiles(Player player)
 {
     // [SC] make sure the tile bag is not empty and not all playable tiles are used
     while (tileBag.Count > 0 && playedTileCount < playabelTileCount)
     {
         TileZeroTile tile = tileBag.ElementAt(0);
         if (player.addTile(tile))
         {
             tileBag.Remove(tile);
             ++playedTileCount;
         }
         else
         {
             break;
         }
     }
 }
Ejemplo n.º 12
0
        // [SC] create a shallow clone of the 2D array
        public static TileZeroTile[,] createBoardCopy(TileZeroTile[,] tileArray)
        {
            if (tileArray == null)
            {
                return(null);
            }

            int rowCount = tileArray.GetLength(0);
            int colCount = tileArray.GetLength(1);

            TileZeroTile[,] newTileArray = new TileZeroTile[rowCount, colCount];

            for (int currRowIndex = 0; currRowIndex < rowCount; currRowIndex++)
            {
                for (int currColIndex = 0; currColIndex < colCount; currColIndex++)
                {
                    newTileArray[currRowIndex, currColIndex] = tileArray[currRowIndex, currColIndex];
                }
            }

            return(newTileArray);
        }
Ejemplo n.º 13
0
        // [2016.12.01]
        protected void putStartingTiles()
        {
            int startCol = virtualBoard.getColCount() / 2 - Cfg.START_TILE_COUNT / 2;
            int startRow = virtualBoard.getRowCount() / 2;

            for (int counter = 0; counter < Cfg.START_TILE_COUNT; counter++)
            {
                int          currCol = startCol + counter;
                TileZeroTile tile    = (TileZeroTile)tileBag.ElementAt(0);

                int result = putTileOnBoard(startRow, currCol, tile, false);

                // [TODO] need to terminate the game
                if (result == Cfg.NONE)
                {
                    Cfg.log("Error putting starting tiles");
                    break;
                }

                tileBag.Remove(tile);
                ++playedTileCount;
            }
        }
Ejemplo n.º 14
0
        public int isValidMove(int rowIndex, int colIndex, TileZeroTile tile, bool validCheck, TileZeroTile[,] tileArrayP, bool showMsg)
        {
            if (tileArrayP == null)
            {
                tileArrayP = tileArray;
            }

            int horizScore = 0;
            int vertScore  = 0;

            if (rowIndex < 0 || rowIndex >= rowCount)
            {
                if (showMsg)
                {
                    Cfg.log("Invalid row index: " + rowIndex + ".");
                }
                return(Cfg.NONE);
            }

            if (colIndex < 0 || colIndex >= colCount)
            {
                if (showMsg)
                {
                    Cfg.log("Invalid column index: " + colIndex + ".");
                }
                return(Cfg.NONE);
            }

            if (hasTile(rowIndex, colIndex, tileArrayP))
            {
                if (showMsg)
                {
                    Cfg.log("The cell already has a tile.");
                }
                return(Cfg.NONE);
            }

            if (validCheck)
            {
                // [SC] check if there is any tile adjacent to the destinatio position
                if (!hasLeftTile(rowIndex, colIndex, tileArrayP) && !hasRightTile(rowIndex, colIndex, tileArrayP) &&
                    !hasBottomTile(rowIndex, colIndex, tileArrayP) && !hasTopTile(rowIndex, colIndex, tileArrayP)
                    )
                {
                    if (showMsg)
                    {
                        Cfg.log("A new tile should be placed next to the existing one.");
                    }
                    return(Cfg.NONE);
                }

                // [SC] temporarily put the tile
                tileArrayP[rowIndex, colIndex] = tile;

                // [SC] check validity of the horizontal sequence of tiles
                if (hasLeftTile(rowIndex, colIndex, tileArrayP) || hasRightTile(rowIndex, colIndex, tileArrayP))
                {
                    horizScore = isValidSequence(rowIndex, colIndex, Cfg.HORIZONTAL, tileArrayP, showMsg);
                    if (horizScore == Cfg.NONE)
                    {
                        tileArrayP[rowIndex, colIndex] = null;
                        return(Cfg.NONE);
                    }
                    else if (horizScore == Cfg.MAX_SEQ_SCORE)
                    {
                        // [SC] reward for completing a TileZero
                        horizScore = Cfg.TILEZERO_REWARD;
                    }
                }

                // [SC] check validity of the vertical sequence of tiles
                if (hasTopTile(rowIndex, colIndex, tileArrayP) || hasBottomTile(rowIndex, colIndex, tileArrayP))
                {
                    vertScore = isValidSequence(rowIndex, colIndex, Cfg.VERTICAL, tileArrayP, showMsg);
                    if (vertScore == Cfg.NONE)
                    {
                        tileArrayP[rowIndex, colIndex] = null;
                        return(Cfg.NONE);
                    }
                    else if (vertScore == Cfg.MAX_SEQ_SCORE)
                    {
                        // [SC] reward for completing a TileZero
                        vertScore = Cfg.TILEZERO_REWARD;
                    }
                }

                // [SC] remove the temporary tile
                tileArrayP[rowIndex, colIndex] = null;
            }

            return(horizScore + vertScore);
        }
Ejemplo n.º 15
0
 // [2016.12.01]
 // [SC] put a given tile on a specified board position; validCheck is true then verify if the move conforms to game rules
 protected int putTileOnBoard(int rowIndex, int colIndex, TileZeroTile tile, bool validCheck)
 {
     return(virtualBoard.addTile(rowIndex, colIndex, tile, validCheck, null));
 }
Ejemplo n.º 16
0
 public void removeTile(TileZeroTile tile)
 {
     playerTiles.Remove(tile);
 }
Ejemplo n.º 17
0
        // [2016.12.01]
        // [SC] a function for dropping a tile
        public void dropPlayerTile(int playerIndex)
        {
            if (!activeGameFlag)
            {
                return;
            }

            if (playerIndex != activePlayerIndex)
            {
                Cfg.log("It is not your turn!");
                return;
            }

            Player activePlayer = players[activePlayerIndex];

            // [SC] check if player drop tiles
            if (!activePlayer.getCanDrop())
            {
                Cfg.log("Cannot drop a tile after putting a tile on a board!"); // [TODO]
                return;
            }

            // [SC] check if bag has tiles
            if (tileBag.Count == 0)
            {
                Cfg.log("Cannot drop a tile! The bag is empty."); // [TODO]
                return;
            }

            // [SC] check if player tile is selected
            if (!activePlayer.isTileSelected())
            {
                Cfg.log("Select a tile at first!"); // [TODO]
                return;
            }

            TileZeroTile tile = activePlayer.getSelectedTile();

            // [SC] make sure that the tile being dropped is not a replacement tile of previously dropped tile
            if (!tile.getCanDrop())
            {
                Cfg.log("Cannot drop a replacement tile!");
                return;
            }

            foreach (TileZeroTile newTile in tileBag)
            {
                // [SC] make sure that the new tile does not have the same features as the dropped tile
                if (newTile.getColorIndex() == tile.getColorIndex() && newTile.getShapeIndex() == tile.getShapeIndex())
                {
                    continue;
                }

                Cfg.log(String.Format("    Dropped tile {0}. Replaced with tile {1}.", tile.ToString(), newTile.ToString()));

                // [SC] remove the dropped tile from player's stack
                activePlayer.removeTile(tile);
                // [SC] add the dropped tile into the bag
                tileBag.Add(tile);

                // [SC] remove the new tile from the bag
                tileBag.Remove(newTile);
                // [SC] add the new tile to player's stack
                activePlayer.addTile(newTile);
                // [SC] make sure that the new tile cannot be dropped in the same turn
                newTile.setCanDrop(false);

                // [SC] shuffle the bag
                tileBag.Shuffle();

                // [SC] prevent the player from moving tiles into the board
                activePlayer.setCanMove(false);

                break;
            }
        }
Ejemplo n.º 18
0
 public void resetSelected()
 {
     selectedTile = null;
 }
Ejemplo n.º 19
0
        private int isValidSequence(int rowIndex, int colIndex, int orientation, TileZeroTile[,] tileArrayP, bool showMsg)
        {
            int[] uniqueColors     = new int[Cfg.MAX_VAL_INDEX];
            int   uniqueColorCount = 0;

            int[] uniqueShapes     = new int[Cfg.MAX_VAL_INDEX];
            int   uniqueShapeCount = 0;

            int sequenceLength = 0;

            int currRow = rowIndex;
            int currCol = colIndex;

            for (int currIndex = 0; currIndex < Cfg.MAX_VAL_INDEX; currIndex++)
            {
                uniqueColors[currIndex] = Cfg.NONE;
                uniqueShapes[currIndex] = Cfg.NONE;
            }

            // [SC] start with the left-most or top-most tile in the sequence
            if (orientation == Cfg.HORIZONTAL)
            {
                while (currCol > 0 && tileArrayP[currRow, currCol - 1] != null)
                {
                    currCol--;
                }
            }
            else
            {
                while (currRow > 0 && tileArrayP[currRow - 1, currCol] != null)
                {
                    currRow--;
                }
            }

            // [SC] checking the validity of colors and shapes, and color-shape combination of the sequence
            while (currRow < rowCount && currCol < colCount)
            {
                TileZeroTile currTile = tileArrayP[currRow, currCol];

                if (currTile == null)
                {
                    break;
                }

                // [SC] checking the validity of colors
                int currColorIndex = currTile.getColorIndex();
                if (uniqueColors[currColorIndex] == Cfg.NONE)
                {
                    uniqueColors[currColorIndex] = currColorIndex;
                    uniqueColorCount++;
                }
                else if (uniqueColorCount == 1)
                {
                }
                else
                {
                    if (showMsg)
                    {
                        Cfg.log("Invalid color sequence.");
                    }
                    return(Cfg.NONE);
                }

                // [SC] checking the validity of shapes
                int currShapeIndex = currTile.getShapeIndex();
                if (uniqueShapes[currShapeIndex] == Cfg.NONE)
                {
                    uniqueShapes[currShapeIndex] = currShapeIndex;
                    uniqueShapeCount++;
                }
                else if (uniqueShapeCount == 1)
                {
                }
                else
                {
                    if (showMsg)
                    {
                        Cfg.log("Invalid shape sequence.");
                    }
                    return(Cfg.NONE);
                }

                sequenceLength++;

                if (sequenceLength > 1)
                {
                    if ((uniqueColorCount == 1 && uniqueShapeCount == 1) || // [SC] both shape and color are same
                        (uniqueColorCount > 1 && uniqueShapeCount > 1)      // both shape and color are different
                        )
                    {
                        if (showMsg)
                        {
                            Cfg.log("Invalid combination of color and shape.");
                        }
                        return(Cfg.NONE);
                    }
                }

                // [TODO] update row
                if (orientation == Cfg.HORIZONTAL)
                {
                    currCol++;
                }
                else
                {
                    currRow++;
                }
            }

            return(sequenceLength);
        }