// WARNING: Moves requiring rotation must wait until piece has fallen by
        // at least one row.

        public override void GetBestMoveOncePerPiece
        (
            STBoard board,
            STPiece piece,
            bool nextPieceFlag,                  // false == no next piece available or known
            STPiece.STPieceShape nextPieceShape, // None == no piece available or known
            ref int bestRotationDelta,           // 0 or {0,1,2,3}
            ref int bestTranslationDelta         // 0 or {...,-2,-1,0,1,2,...}
        )
        {
            bestRotationDelta    = 0;
            bestTranslationDelta = 0;

            // We are given the current board, and the current piece
            // configuration.  Our goal is to evaluate various possible
            // moves and return the best move we explored.

            PrivateStrategy
            (
                false,
                board,
                piece,
                ref bestRotationDelta,   // 0 or {0,1,2,3}
                ref bestTranslationDelta // 0 or {...,-2,-1,0,1,2,...}
            );
        }
Beispiel #2
0
        public void ServerQueueSubmitPiece(STPiece.STPieceShape shape)
        {
            int pieceIndex = 0;

            pieceIndex = (int)STPiece.GetByteCodeValueOfShape(shape);
            this.mQueue.Add(pieceIndex);
        }
Beispiel #3
0
        // UNUSED:
        //private int PrivateQueueGetItem ( )
        //{
        //    if (this.mQueue.Count <= 0)
        //    {
        //        return (0);
        //    }
        //    int value = (this.mQueue[0]);
        //    this.mQueue.RemoveAt( 0 );
        //    return (value);
        //}

        private void PrivateAdvanceQueue( )
        {
            this.mCachedSelectedPieceShapeCurrent = STPiece.STPieceShape.None;
            this.mCachedSelectedPieceShapeNext    = STPiece.STPieceShape.None;

            if (this.mQueue.Count <= 0)
            {
                return;
            }

            // We definitely have one shape in the queue
            int pieceShapeIndexCurrent = 0;

            pieceShapeIndexCurrent = this.PrivateQueuePeekItem( );

            // Remove the shape from the queue
            this.mQueue.RemoveAt(0);

            // There might be another shape in the queue.  We'll peek.
            int pieceShapeIndexNext = 0;

            pieceShapeIndexNext = this.PrivateQueuePeekItem( );


            // Set current and next piece shapes
            this.mCachedSelectedPieceShapeCurrent =
                STPiece.GetShapeCorrespondingToByteCode((byte)pieceShapeIndexCurrent);

            this.mCachedSelectedPieceShapeNext =
                STPiece.GetShapeCorrespondingToByteCode((byte)pieceShapeIndexNext);
        }
        void PrivateStrategyEvaluate
        (
            STBoard board,
            STPiece piece,
            ref double rating
        )
        {
            rating = 0.0;

            if (false == piece.IsValid( ))
            {
                return;
            }


            // The board was given to us with the piece already committed
            // to the board cells, so we can now collapse any completed
            // (fully-occupied) rows.
            board.CollapseAnyCompletedRows( );


            // Note that this evaluation of pile height is AFTER collapsing
            // any completed rows.
            int pileHeight = 0;

            pileHeight = board.GetPileMaxHeight( );


            // This simplistic strategy only punishes the maximum
            // height of the pile.
            rating = ((-1.0) * (double)pileHeight);
        }
        // WARNING: When you get the "best" rotation and translation
        // from the following function, you must wait until the piece has
        // its origin at least as low as row 0 (zero) instead of its initial
        // row -1 (negative one) if any rotations (1,2,3) are required.
        // Perform all rotations, and then perform translations.  This
        // avoids the problem of getting the piece jammed on the sides
        // of the board where rotation is impossible. ***
        // Also, the following strategy does not take advantage of the
        // possibility of using free-fall and future movements to
        // slide under overhangs and fill them in.

        public static void GetBestMoveOncePerPiece
        (
            STBoard board,
            STPiece piece,
            bool nextPieceFlag,                  // false == no next piece available or known
            STPiece.STPieceShape nextPieceShape, // None == no piece available or known
            ref int bestRotationDelta,           // 0 or {0,1,2,3}
            ref int bestTranslationDelta         // 0 or {...,-2,-1,0,1,2,...}
        )
        {
            bestRotationDelta    = 0;
            bestTranslationDelta = 0;

            STStrategy strategy = null;

            strategy = GetCurrentStrategy();

            if (null == strategy)
            {
                return;
            }

            strategy.GetBestMoveOncePerPiece
            (
                board,
                piece,
                nextPieceFlag,           // false == no next piece available or known
                nextPieceShape,          // None == no piece available or known
                ref bestRotationDelta,   // 0 or {0,1,2,3}
                ref bestTranslationDelta // 0 or {...,-2,-1,0,1,2,...}
            );
        }
Beispiel #6
0
 public virtual void GetBestMoveOncePerPiece
 (
     STBoard board,
     STPiece piece,
     bool nextPieceFlag,                  // false == no next piece available or known
     STPiece.STPieceShape nextPieceShape, // None == no piece available or known
     ref int bestRotationDelta,           // 0 or {0,1,2,3}
     ref int bestTranslationDelta         // 0 or {...,-2,-1,0,1,2,...}
 )
 {
     bestRotationDelta    = 0;
     bestTranslationDelta = 0;
 }
Beispiel #7
0
        private void PrivateAdvanceRandom( )
        {
            int pieceShapeIndexCurrent = 0;

            pieceShapeIndexCurrent =
                this.mSTRandom.GetIntegerInRangeUsingCurrentState(1, 7);

            this.mSTRandom.Advance( );

            int pieceShapeIndexNext = 0;

            pieceShapeIndexNext =
                this.mSTRandom.GetIntegerInRangeUsingCurrentState(1, 7);

            // Set current and next piece shapes
            this.mCachedSelectedPieceShapeCurrent =
                STPiece.GetShapeCorrespondingToByteCode((byte)pieceShapeIndexCurrent);

            this.mCachedSelectedPieceShapeNext =
                STPiece.GetShapeCorrespondingToByteCode((byte)pieceShapeIndexNext);
        }
        public static void HandleVideoCaptureGUI
        (
            GR gr,
            float videoSheetX,
            float videoSheetY,
            float videoSheetWidth,
            float videoSheetHeight,
            STGame game,
            int clientWidth,
            int clientHeight,
            int clientRelativeCursorX,
            int clientRelativeCursorY
        )
        {
            STGameState gameState = game.GetGameState( );


            if (false == game.GameIsSpawnFromVideoCapture( ))
            {
                return;
            }


            gr.glBindTexture
            (
                GR.GL_TEXTURE_2D,
                STEngine.GetVideoProcessing( ).mTextureOpenGLHandleBGR256x256
            );


            float x1 = 0.0f;
            float y1 = 0.0f;
            float x2 = 0.0f;
            float y2 = 0.0f;

            x1 = videoSheetX;
            y1 = videoSheetY;
            x2 = x1 + (videoSheetWidth - 1.0f);
            y2 = y1 + (videoSheetHeight - 1.0f);

            float u1 = 0.0f;
            float v1 = 0.0f;
            float u2 = 0.0f;
            float v2 = 0.0f;

            u1 = 0.0f;
            v1 = 0.0f;
            u2 = 0.5f;
            v2 = 1.0f;

            gr.glEnable(GR.GL_SCISSOR_TEST);
            gr.glScissor((int)(x1), (int)(y1), (int)((x2 - x1) + 1), (int)((y2 - y1) + 1));

            gr.glEnable(GR.GL_TEXTURE_2D);
            gr.glColor3f(1.0f, 1.0f, 1.0f);

            gr.glBegin(GR.GL_QUADS);
            gr.glTexCoord2f(u1, v2);
            gr.glVertex2f(x1, y2);

            gr.glTexCoord2f(u1, v1);
            gr.glVertex2f(x1, y1);

            gr.glTexCoord2f(u2, v1);
            gr.glVertex2f(x2, y1);

            gr.glTexCoord2f(u2, v2);
            gr.glVertex2f(x2, y2);
            gr.glEnd( );

            gr.glDisable(GR.GL_TEXTURE_2D);
            gr.glDisable(GR.GL_SCISSOR_TEST);



            int xTexelMin = 0;
            int yTexelMin = 0;
            int xTexelMax = 0;
            int yTexelMax = 0;


            int xScreenMin = 0;
            int yScreenMin = 0;
            int xScreenMax = 0;
            int yScreenMax = 0;



            // Only listen to the mouse in training/calibration mode
            if (true == gameState.mCalibrationModeFlag)
            {
                if (0 != GetAsyncKeyState(Keys.LButton))
                {
                    // Left button pressed
                    if (0 == gameState.mSelectionState)
                    {
                        gameState.mSelectionState = 1;
                        gameState.mSelectionX1    = clientRelativeCursorX;
                        gameState.mSelectionY1    = ((clientHeight - 1) - clientRelativeCursorY);
                        gameState.mSelectionX2    = clientRelativeCursorX;
                        gameState.mSelectionY2    = ((clientHeight - 1) - clientRelativeCursorY);
                    }
                    else
                    {
                        gameState.mSelectionX2 = clientRelativeCursorX;
                        gameState.mSelectionY2 = ((clientHeight - 1) - clientRelativeCursorY);
                    }
                }
                else
                {
                    // Left button released
                    if (0 == gameState.mSelectionState)
                    {
                        // Nothing to do...
                    }
                    else
                    {
                        gameState.mSelectionState = 0;
                    }
                }

                gr.glEnable(GR.GL_SCISSOR_TEST);
                gr.glScissor(0, 0, clientWidth, clientHeight);

                gr.glColor3f(1.0f, 0.0f, 0.0f);
                gr.glBegin(GR.GL_LINES);

                gr.glVertex2f((float)clientRelativeCursorX - 8.0f, (float)((clientHeight - 1) - clientRelativeCursorY));
                gr.glVertex2f((float)clientRelativeCursorX + 8.0f, (float)((clientHeight - 1) - clientRelativeCursorY));

                gr.glVertex2f((float)clientRelativeCursorX, (float)((clientHeight - 1) - clientRelativeCursorY) - 8.0f);
                gr.glVertex2f((float)clientRelativeCursorX, (float)((clientHeight - 1) - clientRelativeCursorY) + 8.0f);
                gr.glEnd( );
            }



            if (0 != ((GetAsyncKeyState(Keys.Shift)) & 0x8000))
            {
                if (0 != ((GetAsyncKeyState(Keys.Left)) & 0x8000))
                {
                    gameState.mSelectionX2--;
                }
                if (0 != ((GetAsyncKeyState(Keys.Right)) & 0x8000))
                {
                    gameState.mSelectionX2++;
                }
                if (0 != ((GetAsyncKeyState(Keys.Down)) & 0x8000))
                {
                    gameState.mSelectionY2--;
                }
                if (0 != ((GetAsyncKeyState(Keys.Up)) & 0x8000))
                {
                    gameState.mSelectionY2++;
                }
            }
            else
            {
                if (0 != ((GetAsyncKeyState(Keys.Left)) & 0x8000))
                {
                    gameState.mSelectionX1--;
                }
                if (0 != ((GetAsyncKeyState(Keys.Right)) & 0x8000))
                {
                    gameState.mSelectionX1++;
                }
                if (0 != ((GetAsyncKeyState(Keys.Down)) & 0x8000))
                {
                    gameState.mSelectionY1--;
                }
                if (0 != ((GetAsyncKeyState(Keys.Up)) & 0x8000))
                {
                    gameState.mSelectionY1++;
                }
            }



            xScreenMin = gameState.mSelectionX1;
            yScreenMin = gameState.mSelectionY1;
            xScreenMax = gameState.mSelectionX2;
            yScreenMax = gameState.mSelectionY2;



            xTexelMin = (int)(256.0f * (((float)xScreenMin - videoSheetX) / videoSheetHeight));
            yTexelMin = (int)(256.0f * (((float)yScreenMin - videoSheetY) / videoSheetHeight));
            xTexelMax = (int)(256.0f * (((float)xScreenMax - videoSheetX) / videoSheetHeight));
            yTexelMax = (int)(256.0f * (((float)yScreenMax - videoSheetY) / videoSheetHeight));

            int disregard = 0;

            if (xTexelMin < 0)
            {
                disregard = 1;
                xTexelMin = 0;
            }
            if (yTexelMin < 0)
            {
                disregard = 1;
                yTexelMin = 0;
            }
            if (xTexelMax < 0)
            {
                disregard = 1;
                xTexelMax = 0;
            }
            if (yTexelMax < 0)
            {
                disregard = 1;
                yTexelMax = 0;
            }

            if (xTexelMin > 255)
            {
                disregard = 1;
                xTexelMin = 255;
            }
            if (yTexelMin > 255)
            {
                disregard = 1;
                yTexelMin = 255;
            }
            if (xTexelMax > 255)
            {
                disregard = 1;
                xTexelMax = 255;
            }
            if (yTexelMax > 255)
            {
                disregard = 1;
                yTexelMax = 255;
            }

            if (xTexelMin > xTexelMax)
            {
                int swap = xTexelMin;
                xTexelMin = xTexelMax;
                xTexelMax = swap;
            }

            if (yTexelMin > yTexelMax)
            {
                int swap = yTexelMin;
                yTexelMin = yTexelMax;
                yTexelMax = swap;
            }


            // Only set region if in training mode!
            if ((true == gameState.mCalibrationModeFlag) && (0 == disregard))
            {
                STEngine.GetVideoProcessing( ).SetRegion(xTexelMin, yTexelMin, xTexelMax, yTexelMax);
            }


            STEngine.GetVideoProcessing( ).GetRegion(ref xTexelMin, ref yTexelMin, ref xTexelMax, ref yTexelMax);

            xScreenMin = (int)(videoSheetX + (videoSheetHeight * (float)xTexelMin / 256.0f));
            yScreenMin = (int)(videoSheetY + (videoSheetHeight * (float)yTexelMin / 256.0f));
            xScreenMax = (int)(videoSheetX + (videoSheetHeight * (float)xTexelMax / 256.0f));
            yScreenMax = (int)(videoSheetY + (videoSheetHeight * (float)yTexelMax / 256.0f));


            x1 = videoSheetX;
            y1 = videoSheetY;
            x2 = x1 + (videoSheetWidth - 1.0f);
            y2 = y1 + (videoSheetHeight - 1.0f);


            int currentClassification = STEngine.GetVideoProcessing( ).GetRegionClassification( );

            if (0 == currentClassification)
            {
                // If the previous classification was a PIECE, and the current classification
                // is something different, then submit the piece (which must have fallen
                // by a row by now).
                if ((gameState.mPreviousClassification >= 1) && (gameState.mPreviousClassification <= 7))
                {
                    game.SpawnSpecifiedPieceShape(STPiece.GetShapeCorrespondingToByteCode((byte)gameState.mPreviousClassification));
                }
            }

            gameState.mPreviousClassification = currentClassification;


            Color color;

            color =
                STGameDrawing.GetCellValueColorARGB // Returns WHITE for unknown
                (
                    (byte)currentClassification,    // 0..6
                    false                           // monochrome mode
                );

            float red   = 0.0f;
            float green = 0.0f;
            float blue  = 0.0f;

            red   = (float)(color.R) / 255.0f;
            green = (float)(color.G) / 255.0f;
            blue  = (float)(color.B) / 255.0f;


            gr.glColor3f(red, green, blue);

            gr.glBegin(GR.GL_LINES);

            gr.glVertex2f((float)xScreenMin, (float)yScreenMin);
            gr.glVertex2f((float)xScreenMin, (float)yScreenMax);

            gr.glVertex2f((float)xScreenMax, (float)yScreenMin);
            gr.glVertex2f((float)xScreenMax, (float)yScreenMax);

            gr.glVertex2f((float)xScreenMin, (float)yScreenMin);
            gr.glVertex2f((float)xScreenMax, (float)yScreenMin);

            gr.glVertex2f((float)xScreenMin, (float)yScreenMax);
            gr.glVertex2f((float)xScreenMax, (float)yScreenMax);

            // Horizontal divider
            gr.glVertex2f((float)xScreenMin, (float)((yScreenMin + yScreenMax) / 2));
            gr.glVertex2f((float)xScreenMax, (float)((yScreenMin + yScreenMax) / 2));

            // Vertical dividers
            gr.glVertex2f((float)(xScreenMin + ((xScreenMax - xScreenMin) / 4)), (float)yScreenMin);
            gr.glVertex2f((float)(xScreenMin + ((xScreenMax - xScreenMin) / 4)), (float)yScreenMax);

            gr.glVertex2f((float)(xScreenMin + 2 * ((xScreenMax - xScreenMin) / 4)), (float)yScreenMin);
            gr.glVertex2f((float)(xScreenMin + 2 * ((xScreenMax - xScreenMin) / 4)), (float)yScreenMax);

            gr.glVertex2f((float)(xScreenMin + 3 * ((xScreenMax - xScreenMin) / 4)), (float)yScreenMin);
            gr.glVertex2f((float)(xScreenMin + 3 * ((xScreenMax - xScreenMin) / 4)), (float)yScreenMax);

            gr.glEnd( );

            gr.glDisable(GR.GL_SCISSOR_TEST);
        }
        private double PrivateStrategy
        (
            bool flagCalledFromParentPly,  // True if called from a parent level
            STBoard board,
            STPiece piece,
            ref int bestRotationDelta,    // 0 or {0,1,2,3}
            ref int bestTranslationDelta  // 0 or {...,-2,-1,0,1,2,...}
        )
        {
            if (false == piece.IsValid( ))
            {
                return(0.0);
            }


            int    currentBestTranslationDelta = 0;
            int    currentBestRotationDelta    = 0;
            double currentBestMerit            = (-1.0e+20); // Really bad!

            int    trialTranslationDelta = 0;
            int    trialRotationDelta    = 0;
            double trialMerit            = 0.0;

            bool moveAcceptable = false;
            int  count          = 0;

            STBoard tempBoard = new STBoard( );
            STPiece tempPiece = new STPiece( );



            int maxOrientations = 0;

            maxOrientations =
                STPiece.GetMaximumOrientationsOfShape(piece.GetShape( ));



            for
            (
                trialRotationDelta = 0;
                trialRotationDelta < maxOrientations;
                trialRotationDelta++
            )
            {
                // Make temporary copy of piece, and rotate the copy.
                tempPiece.CopyFrom(piece);
                for (count = 0; count < trialRotationDelta; count++)
                {
                    tempPiece.Rotate( );
                }


                // Determine the translation limits for this rotated piece.
                bool moveIsPossible = false;
                int  minDeltaX      = 0;
                int  maxDeltaX      = 0;
                board.DetermineAccessibleTranslationsForPieceOrientation
                (
                    tempPiece,
                    ref moveIsPossible,
                    ref minDeltaX,    // left limit
                    ref maxDeltaX     // right limit
                );


                // Consider all allowed translations for the current rotation.
                if (true == moveIsPossible)
                {
                    for
                    (
                        trialTranslationDelta = minDeltaX;
                        trialTranslationDelta <= maxDeltaX;
                        trialTranslationDelta++
                    )
                    {
                        // Evaluate this move

                        // Copy piece to temp and rotate and translate
                        tempPiece.CopyFrom(piece);
                        for (count = 0; count < trialRotationDelta; count++)
                        {
                            tempPiece.Rotate( );
                        }
                        tempPiece.Translate(trialTranslationDelta, 0);

                        moveAcceptable =
                            board.DetermineIfPieceIsWithinBoardAndDoesNotOverlapOccupiedCells
                            (
                                tempPiece
                            );

                        if (true == moveAcceptable)
                        {
                            // Because the piece can BE (not necessarily GET) at the goal
                            // horizontal translation and orientation, it's worth trying
                            // out a drop and evaluating the move.
                            tempBoard.CopyFrom(board);


                            tempBoard.FullDropAndCommitPieceToBoard
                            (
                                tempPiece
                            );

                            // Pierre Dellacherie (France) Board & Piece Evaluation Function
                            this.PrivateStrategyEvaluate
                            (
                                tempBoard,
                                tempPiece,
                                ref trialMerit
                            );

                            // If this move is better than any move considered before,
                            // or if this move is equally ranked but has a higher priority,
                            // then update this to be our best move.
                            if (trialMerit > currentBestMerit)
                            {
                                currentBestMerit            = trialMerit;
                                currentBestTranslationDelta = trialTranslationDelta;
                                currentBestRotationDelta    = trialRotationDelta;
                            }
                        }
                    }
                }
            }


            // commit to this move
            bestTranslationDelta = currentBestTranslationDelta;
            bestRotationDelta    = currentBestRotationDelta;

            return(currentBestMerit);
        }
        // The following one-ply board evaluation function is adapted from the
        // "xtris" application (multi-player Tetris for the X Window system),
        // created by Roger Espel Llima <*****@*****.**>
        //
        // From the "xtris" documentation:
        //
        //   "The values for the coefficients were obtained with a genetic algorithm
        //   using a population of 50 sets of coefficients, calculating 18 generations
        //   in about 500 machine-hours distributed among 20-odd Sparc workstations.
        //   This resulted in an average of about 50,000 completed lines."
        //
        // The following people contributed "ideas for the bot's decision algorithm":
        //
        // Laurent Bercot      <*****@*****.**>
        // Sebastien Blondeel  <*****@*****.**>
        //
        //
        // The algorithm computes 6 values on the whole pile:
        //
        // [1] height   = max height of the pieces in the pile
        // [2] holes    = number of holes (empty positions with a full position somewhere
        //                above them)
        // [3] frontier = length of the frontier between all full and empty zones
        //		            (for each empty position, add 1 for each side of the position
        //		            that touches a border or a full position).
        // [4] drop     = how far down we're dropping the current brick
        // [5] pit      = sum of the depths of all places where a long piece ( ====== )
        //                would be needed.
        // [6] ehole    = a kind of weighted sum of holes that attempts to calculate
        //                how hard they are to fill.
        //
        // droppedPieceRow is the row where we're dropping the piece,
        // which is already in the board.  Note that full lines have not been
        // dropped, so we need to do special tests to skip them.


        void PrivateStrategyEvaluate
        (
            STBoard board,
            STPiece piece,
            ref double rating
        )
        {
            rating = 0.0;

            if (false == piece.IsValid( ))
            {
                return;
            }

            int width  = 0;
            int height = 0;

            width  = board.GetWidth( );
            height = board.GetHeight( );


            int pieceDropDistance = 0;

            pieceDropDistance = (height - piece.GetY());



            int coeff_f      = 260;
            int coeff_height = 110;
            int coeff_hole   = 450;
            int coeff_y      = 290;
            int coeff_pit    = 190;
            int coeff_ehole  = 80;


            int[] lineCellTotal = new int [(1 + 20 + 200)];
            int[] lin           = new int [(1 + 20 + 200)];
            int[] hol           = new int  [(1 + 10 + 200) * (1 + 20 + 400)];
            int[] blockedS      = new int[(1 + 10 + 200)];

            // If width is greater than 200, or height is greater than 400,
            // just give up. Really, this algorithm needs to be repaired to
            // avoid the use of memory!
            if (width > 200)
            {
                return;
            }
            if (height > 400)
            {
                return;
            }



            int x = 0;
            int y = 0;


            // NOTE: ALL ARRAYS ARE ACCESSED WITH 0 BEING FIRST ELEMENT

            // Fill lineCellTotal[] with total cells in each row.

            for (y = 1; y <= height; y++)
            {
                lineCellTotal[(y - 1)] = 0;
                for (x = 1; x <= width; x++)
                {
                    if (board.GetCell(x, y) > 0)
                    {
                        lineCellTotal[(y - 1)]++;
                    }
                }
            }



            // Clobber blocked column array

            for (x = 1; x <= width; x++)
            {
                blockedS[(x - 1)] = (-1);
            }



            // Clear Lin array.

            for (y = 1; y <= height; y++)
            {
                lin[(y - 1)] = 0;
            }



            // Embedded Holes

            int eHoles = 0;

            for (y = height; y >= 1; y--)               // Top-to-Bottom
            {
                for (x = 1; x <= width; x++)
                {
                    if (board.GetCell(x, y) > 0)
                    {
                        hol     [(width * (y - 1)) + (x - 1)] = 0;
                        blockedS[(x - 1)] = y;
                    }
                    else
                    {
                        hol     [(width * (y - 1)) + (x - 1)] = 1;
                        if (blockedS[(x - 1)] >= 0)
                        {
                            int y2 = 0;

                            y2 = blockedS[(x - 1)];

                            // If this more than two rows ABOVE current row, set
                            // to exactly two rows above.
                            if (y2 > (y + 2))
                            {
                                y2 = (y + 2);
                            }

                            // Descend to current row

                            for ( ; y2 > y; y2--)
                            {
                                if (board.GetCell(x, y2) > 0)
                                {
                                    hol[(width * (y - 1)) + (x - 1)] += lin[(y2 - 1)];
                                }
                            }
                        }
                        lin[(y - 1)] += hol[(width * (y - 1)) + (x - 1)];
                        eHoles       += hol[(width * (y - 1)) + (x - 1)];
                    }
                }
            }



            // Determine Max Height

            int maxHeight = 0;

            for (x = 1; x <= width; x++)
            {
                for (y = height; y >= 1; y--)                   // Top-to-Bottom
                {
                    // If line is complete, ignore it for Max Height purposes...
                    if (width == lineCellTotal[(y - 1)])
                    {
                        continue;
                    }

                    if ((y > maxHeight) &&
                        (board.GetCell(x, y) > 0))
                    {
                        maxHeight = y;
                    }
                }
            }



            // Count buried holes

            int holes   = 0;
            int blocked = 0;

            for (x = 1; x <= width; x++)
            {
                blocked = 0;

                for (y = height; y >= 1; y--)                   // Top-to-Bottom
                {
                    // If line is complete, skip it!
                    if (width == lineCellTotal[(y - 1)])
                    {
                        continue;
                    }

                    if (board.GetCell(x, y) > 0)
                    {
                        blocked = 1;                          // We encountered an occupied cell; all below is blocked
                    }
                    else
                    {
                        // All of the following is in the context of the cell ( x, y )
                        // being UN-occupied.

                        // If any upper row had an occupied cell in this column, this
                        // unoccupied cell is considered blocked.
                        if (0 != blocked)
                        {
                            holes++;                             // This unoccupied cell is buried; it's a hole.
                        }
                    }
                }
            }



            // Count Frontier

            int frontier = 0;

            for (x = 1; x <= width; x++)
            {
                for (y = height; y >= 1; y--)                   // Top-to-Bottom
                {
                    // If line is complete, skip it!
                    if (width == lineCellTotal[(y - 1)])
                    {
                        continue;
                    }

                    if (0 == board.GetCell(x, y))
                    {
                        // All of the following is in the context of the cell ( x, y )
                        // being UN-occupied.

                        // If row is not the top, and row above this one is occupied,
                        // then this unoccupied cell counts as a frontier.
                        if ((y < height) &&
                            (board.GetCell(x, (y + 1)) > 0))
                        {
                            frontier++;
                        }

                        // If this row is not the bottom, and the row below is occupied,
                        // this unoccupied cell counts as a frontier.
                        if ((y > 1) &&
                            (board.GetCell(x, (y - 1)) > 0))
                        {
                            frontier++;
                        }

                        // If the column is not the first, and the column to the left is
                        // occupied, then this unoccupied cell counts as a frontier.
                        // Or, if this *is* the left-most cell, it is an automatic frontier.
                        //  (since the beyond the board is in a sense "occupied")
                        if (((x > 1) &&
                             (board.GetCell(x - 1, y) > 0)) ||
                            (1 == x))
                        {
                            frontier++;
                        }

                        // If the column is not the right-most, and the column to the right is
                        // occupied, then this unoccupied cell counts as a frontier.
                        // Or, if this *is* the right-most cell, it is an automatic frontier.
                        //  (since the beyond the board is in a sense "occupied")
                        if (((x < width) &&
                             (board.GetCell(x + 1, y) > 0)) ||
                            (width == x))
                        {
                            frontier++;
                        }
                    }
                }
            }



            int v = 0;

            for (x = 1; x <= width; x++)
            {
                // NOTE: The following seems to descend as far as a 2-column-wide
                //       profile can fall for each column.
                // Scan Top-to-Bottom
                y = height;
                while
                (
                    // Line is not below bottom row...
                    (y >= 1) &&
                    // Cell is unoccupied or line is full...
                    ((0 == board.GetCell(x, y)) ||
                     (width == lineCellTotal[(y - 1)])) &&

                    (
                        // (Not left column AND (left is empty OR line full))
                        ((x > 1) &&
                         ((0 == board.GetCell(x - 1, y)) ||
                          (width == lineCellTotal[(y - 1)])))
                        ||                 // ...OR...
                        // (Not right column AND (right is empty OR line full))
                        ((x < width) &&
                         ((0 == board.GetCell(x + 1, y)) ||
                          (width == lineCellTotal[(y - 1)]))))
                )
                {
                    y--;                     // Descend
                }

                // Count how much further we can fall just considering obstacles
                // in our column.
                int p = 0;
                p = 0;
                for (  ;
                       ((y >= 1) && (0 == board.GetCell(x, y)));
                       y--, p++)
                {
                    ;
                }

                // If this is a deep well, it's worth punishing.
                if (p >= 2)
                {
                    v -= (coeff_pit * (p - 1));
                }
            }



            // compute rating by summing weighted factors
            rating  = (float)(v);
            rating -= (float)(coeff_f * frontier);
            rating -= (float)(coeff_height * maxHeight);
            rating -= (float)(coeff_hole * holes);
            rating -= (float)(coeff_ehole * eHoles);
            rating += (float)(coeff_y * pieceDropDistance);                    // Reward drop depth!
        }
Beispiel #11
0
        private double PrivateStrategy
        (
            bool flagCalledFromParentPly,  // True if called from a parent level
            STBoard board,
            STPiece piece,
            ref int bestRotationDelta,    // 0 or {0,1,2,3}
            ref int bestTranslationDelta  // 0 or {...,-2,-1,0,1,2,...}
        )
        {
            if (false == piece.IsValid( ))
            {
                return(0.0);
            }



            int    currentBestTranslationDelta = 0;
            int    currentBestRotationDelta    = 0;
            double currentBestMerit            = (-1.0e20);
            int    currentBestPriority         = 0;

            int    trialTranslationDelta = 0;
            int    trialRotationDelta    = 0;
            double trialMerit            = 0.0;
            int    trialPriority         = 0;

            int  maxOrientations = 0;
            bool moveAcceptable  = false;
            int  count           = 0;



            STBoard tempBoard = new STBoard();
            STPiece tempPiece = new STPiece();



            maxOrientations =
                STPiece.GetMaximumOrientationsOfShape(piece.GetShape());



            for
            (
                trialRotationDelta = 0;
                trialRotationDelta < maxOrientations;
                trialRotationDelta++
            )
            {
                // Make temporary copy of piece, and rotate the copy.

                tempPiece.CopyFrom(piece);

                for (count = 0; count < trialRotationDelta; count++)
                {
                    tempPiece.Rotate();
                }



                // Determine the translation limits for this rotated piece.

                bool moveIsPossible = false;
                int  minDeltaX      = 0;
                int  maxDeltaX      = 0;
                board.DetermineAccessibleTranslationsForPieceOrientation
                (
                    tempPiece,
                    ref moveIsPossible,                   // false==NONE POSSIBLE
                    ref minDeltaX,                        // Left limit
                    ref maxDeltaX                         // Right limit
                );



                // Consider all allowed translations for the current rotation.

                if (true == moveIsPossible)
                {
                    for
                    (
                        trialTranslationDelta = minDeltaX;
                        trialTranslationDelta <= maxDeltaX;
                        trialTranslationDelta++
                    )
                    {
                        // Evaluate this move

                        // Copy piece to temp and rotate and translate
                        tempPiece.CopyFrom(piece);

                        for (count = 0; count < trialRotationDelta; count++)
                        {
                            tempPiece.Rotate( );
                        }

                        tempPiece.Translate(trialTranslationDelta, 0);

                        moveAcceptable =
                            board.DetermineIfPieceIsWithinBoardAndDoesNotOverlapOccupiedCells
                            (
                                tempPiece
                            );

                        if (true == moveAcceptable)
                        {
                            // Since the piece can be (not necessarily GET) at the goal
                            // horizontal translation and orientation, it's worth trying
                            // out a drop and evaluating the move.
                            tempBoard.CopyFrom(board);


                            tempBoard.FullDropAndCommitPieceToBoard(tempPiece);


                            trialPriority = 0;


                            if (true == flagCalledFromParentPly)
                            {
                                // UNUSED: int rowsEliminated = 0;
                                // UNUSED: rowsEliminated =

                                tempBoard.CollapseAnyCompletedRows();


                                double weightTotalShadowedHoles      = (-0.65);
                                double weightPileHeightWeightedCells = (-0.10);
                                double weightSumOfWellHeights        = (-0.20);

                                trialMerit  = (weightTotalShadowedHoles) * (double)(tempBoard.GetTotalShadowedHoles( ));
                                trialMerit += (weightPileHeightWeightedCells) * (double)(tempBoard.GetPileHeightWeightedCells( ));
                                trialMerit += (weightSumOfWellHeights) * (double)(tempBoard.GetSumOfWellHeights( ));
                            }
                            else
                            {
                                double weightRowElimination          = (0.30);
                                double weightTotalOccupiedCells      = (-0.00);
                                double weightTotalShadowedHoles      = (-0.65);
                                double weightPileHeightWeightedCells = (-0.10);
                                double weightSumOfWellHeights        = (-0.20);

                                int rowsEliminated = 0;
                                rowsEliminated = tempBoard.CollapseAnyCompletedRows();
                                // Single Ply (No next piece)
                                // Averages around 1310 rows in 10 games, with a min of 445 and a max of 3710.
                                trialMerit  = (weightRowElimination) * (double)(rowsEliminated);
                                trialMerit += (weightTotalOccupiedCells) * (double)(tempBoard.GetTotalOccupiedCells( ));
                                trialMerit += (weightTotalShadowedHoles) * (double)(tempBoard.GetTotalShadowedHoles( ));
                                trialMerit += (weightPileHeightWeightedCells) * (double)(tempBoard.GetPileHeightWeightedCells( ));
                                trialMerit += (weightSumOfWellHeights) * (double)(tempBoard.GetSumOfWellHeights( ));
                            }



                            // If this move is better than any move considered before,
                            // or if this move is equally ranked but has a higher priority,
                            // then update this to be our best move.
                            if
                            (
                                (trialMerit > currentBestMerit) ||
                                ((trialMerit == currentBestMerit) && (trialPriority > currentBestPriority))
                            )
                            {
                                currentBestPriority         = trialPriority;
                                currentBestMerit            = trialMerit;
                                currentBestTranslationDelta = trialTranslationDelta;
                                currentBestRotationDelta    = trialRotationDelta;
                            }
                        }
                    }
                }
            }


            // Commit to this move
            bestTranslationDelta = currentBestTranslationDelta;
            bestRotationDelta    = currentBestRotationDelta;


            return(currentBestMerit);
        }
Beispiel #12
0
        private double PrivateStrategyNextPiece
        (
            STBoard board,
            STPiece piece,
            STPiece.STPieceShape nextPieceShape, // None == no piece available or known
            ref int bestRotationDelta,           // 0 or {0,1,2,3}
            ref int bestTranslationDelta         // 0 or {...,-2,-1,0,1,2,...}
        )
        {
            if (false == piece.IsValid( ))
            {
                return(0.0);
            }



            int    currentBestTranslationDelta = 0;
            int    currentBestRotationDelta    = 0;
            double currentBestMerit            = (-1.0e20);
            int    currentBestPriority         = 0;

            int    trialTranslationDelta = 0;
            int    trialRotationDelta    = 0;
            double trialMerit            = 0.0;
            int    trialPriority         = 0;

            int  maxOrientations = 0;
            bool moveAcceptable  = false;
            int  count           = 0;



            STBoard tempBoard = new STBoard();
            STPiece tempPiece = new STPiece();



            maxOrientations = STPiece.GetMaximumOrientationsOfShape(piece.GetShape());



            for
            (
                trialRotationDelta = 0;
                trialRotationDelta < maxOrientations;
                trialRotationDelta++
            )
            {
                // Make temporary copy of piece, and rotate the copy.

                tempPiece.CopyFrom(piece);

                for (count = 0; count < trialRotationDelta; count++)
                {
                    tempPiece.Rotate();
                }



                // Determine the translation limits for this rotated piece.

                bool moveIsPossible = false;
                int  minDeltaX      = 0;
                int  maxDeltaX      = 0;
                board.DetermineAccessibleTranslationsForPieceOrientation
                (
                    tempPiece,
                    ref moveIsPossible,                   // false==NONE POSSIBLE
                    ref minDeltaX,                        // Left limit
                    ref maxDeltaX                         // Right limit
                );



                // Consider all allowed translations for the current rotation.

                if (true == moveIsPossible)
                {
                    for
                    (
                        trialTranslationDelta = minDeltaX;
                        trialTranslationDelta <= maxDeltaX;
                        trialTranslationDelta++
                    )
                    {
                        // Evaluate this move

                        // Copy piece to temp and rotate and translate
                        tempPiece.CopyFrom(piece);

                        for (count = 0; count < trialRotationDelta; count++)
                        {
                            tempPiece.Rotate();
                        }

                        tempPiece.Translate(trialTranslationDelta, 0);

                        moveAcceptable =
                            board.DetermineIfPieceIsWithinBoardAndDoesNotOverlapOccupiedCells
                            (
                                tempPiece
                            );

                        if (true == moveAcceptable)
                        {
                            // Since the piece can be (not necessarily GET) at the goal
                            // horizontal translation and orientation, it's worth trying
                            // out a drop and evaluating the move.
                            tempBoard.CopyFrom(board);


                            tempBoard.FullDropAndCommitPieceToBoard(tempPiece);


                            trialPriority = 0;



                            // Okay, now do second move with "Next Piece"
                            int nextPieceBestRotation    = 0;                                // Dummy variable
                            int nextPieceBestTranslation = 0;                                // Dummy variable

                            STPiece nextPiece = new STPiece();
                            nextPiece.SetShape(nextPieceShape);
                            nextPiece.SetX(tempBoard.GetPieceSpawnX());
                            nextPiece.SetY(tempBoard.GetPieceSpawnY() - 1);
                            nextPiece.SetOrientation(1);

                            trialMerit =
                                PrivateStrategy
                                (
                                    true,                             // Not just a single ply; We are calling from a parent ply.
                                    tempBoard,
                                    nextPiece,
                                    ref nextPieceBestRotation,
                                    ref nextPieceBestTranslation
                                );



                            // If this move is better than any move considered before,
                            // or if this move is equally ranked but has a higher priority,
                            // then update this to be our best move.
                            if (
                                (trialMerit > currentBestMerit) ||
                                ((trialMerit == currentBestMerit) && (trialPriority > currentBestPriority))
                                )
                            {
                                currentBestPriority         = trialPriority;
                                currentBestMerit            = trialMerit;
                                currentBestTranslationDelta = trialTranslationDelta;
                                currentBestRotationDelta    = trialRotationDelta;
                            }
                        }
                    }
                }
            }


            // Commit to this move
            bestTranslationDelta = currentBestTranslationDelta;
            bestRotationDelta    = currentBestRotationDelta;


            return(currentBestMerit);
        }
        // The following evaluation function was adapted from Pascal code submitted by:
        // Pierre Dellacherie (France).  (E-mail : [email protected])
        //
        // This amazing one-piece algorithm completes an average of roughly 600 000
        // rows, and often attains 2 000 000 or 2 500 000 rows.  However, the algorithm
        // sometimes completes as few as 15 000 rows.  I am fairly certain that this
        // is NOT due to statistically abnormal patterns in the falling piece sequence.
        //
        // Pierre Dellacherie corresponded with me via e-mail to help me with the
        // conversion of his Pascal code to C++.
        //
        // WARNING:
        //     If there is a single board and piece combination with the highest
        //     'rating' value, it is the best combination.  However, among
        //     board and piece combinations with EQUAL 'rating' values,
        //     the highest 'priority' value wins.
        //
        //     So, the complete rating is: { rating, priority }.


        void  PrivateStrategyEvaluate
        (
            STBoard board,
            STPiece piece,
            ref double rating,
            ref int priority
        )
        {
            rating   = 0.0;
            priority = 0;

            if (false == piece.IsValid())
            {
                return;
            }



            int boardWidth  = 0;
            int boardHeight = 0;

            boardWidth  = board.GetWidth();
            boardHeight = board.GetHeight();



            int pieceMinX = 0;
            int pieceMinY = 0;
            int pieceMaxX = 0;
            int pieceMaxY = 0;

            piece.GetTranslatedBoundingRectangle
                (ref pieceMinX, ref pieceMinY, ref pieceMaxX, ref pieceMaxY);


            // Landing Height (vertical midpoint)

            double landingHeight = 0.0;

            landingHeight = 0.5 * (double)(pieceMinY + pieceMaxY);



            int completedRows = 0;

            completedRows = board.GetTotalCompletedRows();

            int erodedPieceCellsMetric = 0;

            if (completedRows > 0)
            {
                // Count piece cells eroded by completed rows before doing collapse on pile.
                int pieceCellsEliminated = 0;
                pieceCellsEliminated = board.CountPieceCellsEliminated(piece);

                // Now it's okay to collapse completed rows
                board.CollapseAnyCompletedRows();

                // Weight eroded cells by completed rows
                erodedPieceCellsMetric = (completedRows * pieceCellsEliminated);
            }



            // Note that this evaluation of pile height is AFTER collapsing
            // any completed rows.
            int pileHeight = 0;

            pileHeight = board.GetPileMaxHeight();

            // Each empty row (above pile height) has two (2) "transitions"
            // (We could call ref_Board.GetTransitionCountForRow( y ) for
            // these unoccupied rows, but this is an optimization.)
            int boardRowTransitions = 0;

            boardRowTransitions = 2 * (boardHeight - pileHeight);

            // Only go up to the pile height, and later we'll account for the
            // remaining rows transitions (2 per empty row).
            int y = 0;

            for (y = 1; y <= pileHeight; y++)
            {
                boardRowTransitions += (board.GetTransitionCountForRow(y));
            }



            int boardColumnTransitions = 0;
            int boardBuriedHoles       = 0;
            int boardWells             = 0;
            int x = 0;

            for (x = 1; x <= boardWidth; x++)
            {
                boardColumnTransitions += board.GetTransitionCountForColumn(x);
                boardBuriedHoles       += board.GetBuriedHolesForColumn(x);
                boardWells             += board.GetAllWellsForColumn(x);
            }



            // Final Rating


            rating  = (0.0);
            rating += ((-1.0) * (landingHeight));
            rating += ((1.0) * ((double)(erodedPieceCellsMetric)));
            rating += ((-1.0) * ((double)(boardRowTransitions)));
            rating += ((-1.0) * ((double)(boardColumnTransitions)));
            rating += ((-4.0) * ((double)(boardBuriedHoles)));
            rating += ((-1.0) * ((double)(boardWells)));

            // EXPLANATION:
            //   [1] Punish landing height
            //   [2] Reward eroded piece cells
            //   [3] Punish row    transitions
            //   [4] Punish column transitions
            //   [5] Punish buried holes (cellars)
            //   [6] Punish wells



#if DEBUGGING_PRINT_STATEMENTS
            STEngine.GetConsole().AddLine
            (
                " D:" + (21.0 - landingHeight)
                + " R:" + erodedPieceCellsMetric
                + " RC:" + (-boardRowTransitions)
                + " CC:" + (-boardColumnTransitions)
                + " H:" + (-4 * boardBuriedHoles)
                + " W:" + (-boardWells)
            );
#endif



            // PRIORITY:
            //   Priority is further differentiation between possible moves.
            //   We further rate moves accoding to the following:
            //            * Reward deviation from center of board
            //            * Reward pieces to the left of center of the board
            //            * Punish rotation
            //   Priority is less important than the rating, but among equal
            //   ratings we select the option with the greatest priority.
            //   In principle we could simply factor priority in to the rating,
            //   as long as the priority was less significant than the smallest
            //   variations in rating, but for large board widths (>100), the
            //   risk of loss of precision in the lowest bits of the rating
            //   is too much to tolerate.  So, this priority is stored in a
            //   separate variable.

            int absoluteDistanceX = 0;
            absoluteDistanceX = (piece.GetX() - board.GetPieceSpawnX());
            if (absoluteDistanceX < 0)
            {
                absoluteDistanceX = (-(absoluteDistanceX));
            }

            priority  = 0;
            priority += (100 * absoluteDistanceX);
            if (piece.GetX() < board.GetPieceSpawnX())
            {
                priority += 10;
            }
            priority -= (piece.GetOrientation( ) - 1);
        }