gridstatus.cpp
来自「Source code (C++) of the Amoebax game fo」· C++ 代码 · 共 389 行
CPP
389 行
//// Cross-platform free Puyo-Puyo clone.// Copyright (C) 2006, 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_#include <cassert>#include <limits>#include "Amoeba.h"#include "Grid.h"#include "GridStatus.h"using namespace Amoebax;////// \brief Default constructor.////// Creates an empty state.///GridStatus::GridStatus (void): m_State (Grid::k_GridWidth * Grid::k_GridHeight, Amoeba::ColourNone){}////// \brief Constructor.////// \param state The current state of the grid.///GridStatus::GridStatus (const std::vector<Amoeba::Colour> &state): m_State (state){ assert ( m_State.size () == (Grid::k_GridWidth * Grid::k_GridHeight) && "The state size is not the same as the grid size." );}////// \brief Checks what would happen in a given position.////// Checks what would happen if the falling pair falls in the given/// positions. This is mainly used for AI players.////// \note This code assumes that the main amoeba will fall first and then/// will fall the satellite amoeba. This means that the satellite amoeba/// can't be below the main amoeba for this function to work properly.////// \param main The position of the main falling amoeba./// \param satellite The position of the satellite falling amoeba./// \param result The result of the position of the pair.///voidGridStatus::checkPositions (const Grid::FallingAmoeba &main, const Grid::FallingAmoeba &satellite, PositionResult &result){ // Store the main colour. Amoeba::Colour mainColour = main.amoeba->getColour (); // Find the Y position of the main amoeba. int mainY = Grid::k_GridHeight - 1; while ( Amoeba::ColourNone != getAmoebaColourAt (main.x, mainY) ) { mainY--; } // Place the main amoeba as if it already fell. setAmoebaColourAt (main.x, mainY, mainColour); // Store the satellite colour. Amoeba::Colour satelliteColour = satellite.amoeba->getColour (); // Find the Y position of the satellite amoeba. int satelliteY = Grid::k_GridHeight - 1; while ( Amoeba::ColourNone != getAmoebaColourAt (satellite.x, satelliteY) ) { satelliteY--; } // Place the main amoeba as if it already fell. setAmoebaColourAt (satellite.x, satelliteY, satelliteColour); result.ghostAmoebasRemoved = 0; // Now check the groups that the main and satellite amoebas can make. { uint16_t stepChainGroup = 0; std::set<Position> visitedPositions; Group group; Group ghosts; // Main amoeba. makeGroup (group, ghosts, main.x, mainY, visitedPositions); if ( 4 <= group.size () ) { stepChainGroup += group.size (); removeAmoebaGroup (group); result.ghostAmoebasRemoved += ghosts.size (); removeAmoebaGroup (ghosts); } // Satellite amoeba. makeGroup (group, ghosts, satellite.x, satelliteY, visitedPositions); if ( 4 <= group.size () ) { stepChainGroup += group.size (); removeAmoebaGroup (group); result.ghostAmoebasRemoved += ghosts.size (); removeAmoebaGroup (ghosts); } result.stepChains.clear (); result.stepChains.push_back (stepChainGroup); } // Find the amoebas that are left floating and make them fall, check // for groups and remove the groups, until there are no more floating // amoebas. Group floatingAmoebas (findFloatingAmoebas ()); while ( !floatingAmoebas.empty () ) { std::vector<Group> groups (makeFloatingAmoebasFall (floatingAmoebas)); std::vector<Group>::const_iterator currentGroup = groups.begin (); uint16_t stepChainGroup = 0; for ( bool isGhostGroup = false ; currentGroup != groups.end () ; ++currentGroup, isGhostGroup = !isGhostGroup ) { // For each floating there's two consecutive groups: one for // the "regular" amoebas and the other for the ghosts groups. if ( isGhostGroup ) { result.ghostAmoebasRemoved += currentGroup->size (); } else { stepChainGroup += currentGroup->size (); } removeAmoebaGroup (*currentGroup); } result.stepChains.push_back (stepChainGroup); floatingAmoebas = findFloatingAmoebas (); } // Now get the height of each column, accumulate the height to then // compute the mean, store the maximum and also store separatelly the // third column's height. result.heightMax = std::numeric_limits<uint16_t>::min (); result.heightMean = 0; result.heightThirdColumn = 0; for ( uint8_t currentColumn = 0 ; currentColumn < Grid::k_GridWidth ; ++currentColumn ) { // Get the column's height. uint16_t y = Grid::k_GridHeight - 1; uint16_t height = 0; while ( Amoeba::ColourNone != getAmoebaColourAt (currentColumn, y) ) { --y; ++height; } // Accumulate the height to compute the mean and store it if it's max. result.heightMax = std::max (result.heightMax, height); result.heightMean += height; // If we are on the third column (i.e, column 2) store it. if ( 2 == currentColumn ) { result.heightThirdColumn = height; } } // Now compute the actual mean. result.heightMean /= Grid::k_GridWidth; // Get the number of groups of less than 4 amoebas (i.e., at this state // just the groups since there's no group of 4 or more amoebas.) { std::set<Position> visitedPositions; result.groups.clear (); result.groupsAmoebasNumber = 0; for ( int16_t currentY = 0 ; currentY < Grid::k_GridHeight ; ++currentY ) { for ( int16_t currentX = 0 ; currentX < Grid::k_GridWidth ; ++currentX ) { Group group; Group ghosts; makeGroup (group, ghosts, currentX, currentY, visitedPositions); if ( 1 < group.size () ) { result.groupsAmoebasNumber += group.size (); result.groups.push_back (group.size ()); } } } }}////// \brief Finds all floating amoebas.////// A floating amoeba is just an amoeba that has lost its supporting/// amoeba and so it's "floating" on the grid.////// \return The list of all floating amoebas starting from the lower/// grid's line.///std::vector<GridStatus::Position>GridStatus::findFloatingAmoebas (void) const{ // Check all but the last line. Group floatingAmoebas; for ( int16_t row = Grid::k_GridHeight - 2 ; row >= 0 ; --row ) { for ( int16_t column = 0 ; column < Grid::k_GridWidth ; ++column ) { if ( Amoeba::ColourNone != getAmoebaColourAt (column, row) && Amoeba::ColourNone == getAmoebaColourAt (column, row + 1) ) { floatingAmoebas.push_back (std::make_pair (column, row)); } } } return floatingAmoebas;}////// \brief Gets the amoeba's colour at a given grid's position.////// \param x The X position of the grid to get the amoeba's colour from./// \param y The Y position of the grid to get the amoeba's colour from./// \return The amoeba's colour at position \p x and \p y or Amoeba::ColourNone/// if there is no amoeba at this position or the position is/// incorrect (i.e., out of grid's limits.)///inline Amoeba::ColourGridStatus::getAmoebaColourAt (int16_t x, int16_t y) const{ if ( 0 <= x && x < Grid::k_GridWidth && 0 <= y && y < Grid::k_GridHeight ) { return m_State[y * Grid::k_GridWidth + x]; } return Amoeba::ColourNone;}////// \brief Makes the floating amoebas fall into they right position.////// Once a floating amoeba is identified, this function just takes it and/// makes it fall until another amoeba is found or the bottom-most line/// is reached. Then it checks if it can make more groups and stores it.////// \param floatingAmoebas The floating amoebas to make fall./// \return A list with all groups made when the amoebas felt.///std::vector<GridStatus::Group>GridStatus::makeFloatingAmoebasFall (const Group &floatingAmoebas){ Group positionsToCheck; for ( Group::const_iterator currentAmoeba = floatingAmoebas.begin () ; currentAmoeba != floatingAmoebas.end () ; ++currentAmoeba ) { int x = currentAmoeba->first; int y = currentAmoeba->second; Amoeba::Colour colour = getAmoebaColourAt (x, y); setAmoebaColourAt (x, y, Amoeba::ColourNone); y = Grid::k_GridHeight - 1; while ( Amoeba::ColourNone != getAmoebaColourAt (x, y) ) { --y; } setAmoebaColourAt (x, y, colour); positionsToCheck.push_back (std::make_pair (x, y)); } // Now check if we can make groups from the floating amoebas once fallen. std::vector<Group> floatingGroups; std::set<Position> visitedPositions; for ( Group::const_iterator currentPosition = positionsToCheck.begin () ; currentPosition != positionsToCheck.end () ; ++currentPosition ) { Group group; Group ghosts; makeGroup (group, ghosts, currentPosition->first, currentPosition->second, visitedPositions); if ( 4 <= group.size () ) { floatingGroups.push_back (group); floatingGroups.push_back (ghosts); } } return floatingGroups;}////// \brief Makes a group of equal coloured amoebas recursively.////// \param group The group vector to save the group member found to./// \param ghosts The ghosts amoebas that are in contact with the group./// \param x The X position to look for a possible group candidate./// \param y The Y position to look for a possible group candidate./// \param visitedPositions The set of the already visited position by the/// algorithm. Initially, this should be empty./// \param groupColour The colour of the amoeba to be part of the group./// \param initialAmoeba Tells if the amoeba at \p x and \p y should be the/// first amoeba of the group and use its colour to check/// for more amoebas.///voidGridStatus::makeGroup (Group &group, Group &ghosts, int16_t x, int16_t y, std::set<Position> &visitedPositions, Amoeba::Colour groupColour, bool initialAmoeba){ Position currentPosition (std::make_pair (x, y)); // Only check this position if we didn't visited it yet. if ( visitedPositions.end () == visitedPositions.find (currentPosition) ) { // If there's any amoeba at the given position, check if is of the // same colour as the others in the group. Amoeba::Colour colour = getAmoebaColourAt (x, y); if ( Amoeba::ColourNone != colour ) { // Add the current position to the already visited positions. visitedPositions.insert (currentPosition); // If this amoeba is the first one, then we need to use its // colour as the group's colour. if ( initialAmoeba ) { groupColour = colour; } // Can't make groups of ghost amoebas. If this amoeba is // a ghosts, then set it to the ghosts groups and don't look // any further. if ( Amoeba::ColourGhost == colour ) { ghosts.push_back (currentPosition); } // Otherwise, if the amoeba's colour is the same as the // group's colour, add it to the group vector and check for its // neighbours. else if ( colour == groupColour ) { group.push_back (currentPosition); makeGroup (group, ghosts, x, y - 1, visitedPositions, groupColour, false); makeGroup (group, ghosts, x + 1, y, visitedPositions, groupColour, false); makeGroup (group, ghosts, x, y + 1, visitedPositions, groupColour, false); makeGroup (group, ghosts, x - 1, y, visitedPositions, groupColour, false); } } }}////// \brief Removes a group of amoebas from the grid.////// \param group The group of amoebas to remove from the grid.///voidGridStatus::removeAmoebaGroup (const Group &group){ for ( Group::const_iterator currentPosition = group.begin () ; currentPosition != group.end () ; ++currentPosition ) { setAmoebaColourAt (currentPosition->first, currentPosition->second, Amoeba::ColourNone); }}////// \brief Sets the amoeba's colour at a given grid's position.////// \param x The X position to set the amoeba's colour to./// \param y The Y position to set the amoeba's colour to./// \param colour The amoeba's colour to set at grid's position \p x and \p y.///inline voidGridStatus::setAmoebaColourAt (int16_t x, int16_t y, Amoeba::Colour colour){ if ( 0 <= x && x < Grid::k_GridWidth && 0 <= y && y < Grid::k_GridHeight ) { m_State[y * Grid::k_GridWidth + x] = colour; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?