aiplayer.cpp

来自「Source code (C++) of the Amoebax game fo」· C++ 代码 · 共 689 行 · 第 1/2 页

CPP
689
字号
//// Cross-platform free Puyo-Puyo clone.// Copyright (C) 2007 Emma's software//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA//#if defined (HAVE_CONFIG_H)#include <config.h>#endif // !HAVE_CONFIG_H#include <cassert>#include <limits>#include "AIPlayer.h"#include "FrameManager.h"using namespace Amoebax;////// \brief Default constructor.////// \param side The player's grid side./// \param timeToWaitForNextMove The average time the player///                              waits between moves, in ms./// \param timeDeviation The max. number of milliseconds to add or///                      substracts to the average time to move///                      (minimum is 1ms.)///AIPlayer::AIPlayer (IPlayer::PlayerSide side,                    uint32_t timeToWaitForNextMove,                    uint32_t timeDeviation):    IPlayer (side),    m_BestMove (),    m_BestScore (std::numeric_limits<int32_t>::min ()),    m_FallingPairAtPosition (false),    m_HaveFinalMove (false),    m_PairToCheck (CheckingCurrentFallingPair),    m_TimeDeviation (timeDeviation),    m_TimeOfNextMove (0),    m_TimeToWaitForNextMove (timeToWaitForNextMove),    m_WaitingNextPair (true){    assert ( 0 <= m_TimeDeviation &&            "The time deviation must be greater than 0!" );}////// \brief Tells if the AI player can move.////// Checks if the current time is past the time of the next move,/// letting the player move.////// \return \a true if the player can make the next move,///         \a false otherwise.///boolAIPlayer::canMove (void) const{    return FrameManager::getCurrentTime () > m_TimeOfNextMove;}////// \brief Checks all possible possitions of an state.////// \param state The state to check all its positions./// \param gridState The current grid state to make the check with./// \param parentScore The score of the parent's state.///voidAIPlayer::checkAllPositionsOf (State &state, const GridStatus &gridState,                               int32_t parentScore){    bool initialPosition = true;    state.move.rotation = RotationLeft;    do    {        if ( initialPosition )        {            initialPosition = false;        }        else        {            // Next rotation.            switch ( state.move.rotation )            {                case RotationLeft:                    state.move.rotation = RotationTop;                    break;                case RotationTop:                    state.move.rotation = RotationRight;                    break;                case RotationRight:                default:                    state.move.rotation = RotationBottom;                    break;            }        }        switch ( state.move.rotation )        {            case RotationBottom:                state.move.main.x = 0;                state.move.satellite.x = 0;                state.endX = Grid::k_GridWidth;                // swap the satellite and main amoebas, so they will                // be exactly the same case as RotationTop, but in reverse                // order.                std::swap (state.move.main, state.move.satellite);                break;            case RotationLeft:                state.move.main.x = 1;                state.move.satellite.x = 0;                state.endX = Grid::k_GridWidth - 1;                break;            case RotationRight:                state.move.main.x = 0;                state.move.satellite.x = 1;                state.endX = Grid::k_GridWidth - 1;                break;            case RotationTop:                state.move.main.x = 0;                state.move.satellite.x = 0;                state.endX = Grid::k_GridWidth;                break;            default:                state.move.rotation = RotationLeft;                state.move.main.x = 1;                state.move.satellite.x = 0;                state.endX = Grid::k_GridWidth - 1;                break;        }        // Check all positions.        for ( state.currentX = 0 ; state.currentX < state.endX ; ++state.currentX )        {            state.gridState = gridState;            GridStatus::PositionResult result;            state.gridState.checkPositions (state.move.main,                                            state.move.satellite, result);            state.score = parentScore + computeScore (result);            if ( state.score > getBestScore () )            {                // Take into account that satellite and main are                // reversed when the satellite is at bottom.                if ( RotationBottom == m_BestMove.rotation )                {                    std::swap (m_PairState[0].move.main,                               m_PairState[0].move.satellite);                }                setBestMove (m_PairState[0].move, state.score);                if ( RotationBottom == m_BestMove.rotation )                {                    std::swap (m_PairState[0].move.main,                               m_PairState[0].move.satellite);                }            }            ++state.move.main.x;            ++state.move.satellite.x;        }    }    while ( RotationBottom != state.move.rotation );}////// \brief Checks the next position of the current falling pair.///voidAIPlayer::checkCurrentFallingPair (void){    if ( shouldCheckNextFallingPair () )    {        if ( m_PairState[0].isAtLastPosition () )        {            setHasFinalMove ();        }        else        {            checkNextPositionOf (m_PairState[0], getGrid ()->getState ());            initializeState (m_PairState[1], m_PairState[0].gridState,                             m_PairState[0].score);            setPairToCheck (CheckingNextFallingPair);        }    }    else    {        checkAllPositionsOf (m_PairState[0], getGrid ()->getState (), 0);        setHasFinalMove ();    }}////// \brief Checks all the position of the following (i.e., last) pair.///voidAIPlayer::checkFollowingFallingPair (void){    checkAllPositionsOf (m_PairState[2], m_PairState[1].gridState,                         m_PairState[1].score);    setPairToCheck (CheckingNextFallingPair);}////// \brief Checks if a pair is starting to fall into the grid.////// If the pair has started to fall into the grid then initializes/// the first movement and computes its best score. Then sets the/// AI player in a non-waiting state.///voidAIPlayer::checkIfPairIsAvailable (void){    if ( getGrid ()->hasNewFallingPair () )    {        // Get the current position of the falling pair,        // which should be the center of the grid. This also gets        m_PairState[0].move.main = getGrid ()->getFallingMainAmoeba ();        m_PairState[0].move.satellite = getGrid ()->getFallingSatelliteAmoeba ();        // Also get the next one or two pairs.        if ( shouldCheckNextFallingPair () )        {            m_PairState[1].move.main = getGrid ()->getNextFallingMainAmoeba ();            m_PairState[1].move.satellite = getGrid ()->getNextFallingSatelliteAmoeba ();            if ( shouldCheckFollowingFallingPair () )            {                m_PairState[2].move.main = getGrid ()->getFollowingFallingMainAmoeba ();                m_PairState[2].move.satellite = getGrid ()->getFollowingFallingSatelliteAmoeba ();            }        }        // The best movement is also the initial position, as if we        // don't have a better movement, why waste time moving the falling        m_PairState[0].move.rotation = RotationTop;        setBestMove (m_PairState[0].move, std::numeric_limits<int32_t>::min ());        initializeState (m_PairState[0], getGrid ()->getState ());        setPairToCheck (CheckingCurrentFallingPair);        m_FallingPairAtPosition = false;        m_HaveFinalMove = false;        m_WaitingNextPair = false;    }}////// \brief Checks the next position or all position of the next pair.///voidAIPlayer::checkNextFallingPair (void){    if ( shouldCheckFollowingFallingPair () )    {        if ( m_PairState[1].isAtLastPosition () )        {            setPairToCheck (CheckingCurrentFallingPair);        }        else        {            checkNextPositionOf (m_PairState[1], m_PairState[0].gridState,                                 m_PairState[0].score);            setPairToCheck (CheckingFollowingFallingPair);            checkFollowingFallingPair ();            checkNextFallingPair ();        }    }    else    {        checkAllPositionsOf (m_PairState[1], m_PairState[0].gridState,                             m_PairState[0].score);        setPairToCheck (CheckingCurrentFallingPair);    }}////// \brief Changes the position of the state and computes its score.////// \param state The state to change and to check its score./// \param gridState The current state of the grid to check the///                  position to./// \param parentScore The score of the parent state.///voidAIPlayer::checkNextPositionOf (State &state, const GridStatus &gridState,                               int32_t parentScore){    // If we are not at the end of the current rotation.    if ( state.currentX < state.endX )    {        ++state.currentX;        ++state.move.main.x;        ++state.move.satellite.x;    }    // Otherwise go to the next rotation and start again.    else    {        state.currentX = 1;        switch ( state.move.rotation )        {            case RotationLeft:                state.move.rotation = RotationTop;                state.move.main.x = 0;                state.move.satellite.x = 0;                state.endX = Grid::k_GridWidth;                break;            case RotationTop:                state.move.rotation = RotationRight;                state.move.main.x = 0;                state.move.satellite.x = 1;                state.endX = Grid::k_GridWidth - 1;                break;            case RotationRight:            default:                state.move.rotation = RotationBottom;                state.move.main.x = 0;                state.move.satellite.x = 0;                state.endX = Grid::k_GridWidth;                // swap the satellite and main amoebas, so they will                // be exactly the same case as RotationTop, but in reverse                // order.                std::swap (state.move.main, state.move.satellite);                break;        }    }    state.gridState = gridState;    GridStatus::PositionResult result;    state.gridState.checkPositions (state.move.main, state.move.satellite,                                    result);    state.score = parentScore + computeScore (result);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?