File indexing completed on 2024-04-28 04:01:57

0001 /***************************************************************************
0002 *   KBlocks, a falling blocks game by KDE                                 *
0003 *   SPDX-FileCopyrightText: 2010 University Freiburg <squall.leonhart.cai@gmail.com> *
0004 *                                                                          *
0005 *   SPDX-License-Identifier: GPL-2.0-or-later
0006 ***************************************************************************/
0007 #include "KBlocksAIPlanner.h"
0008 #include "KBlocksAILog.h"
0009 
0010 /* ############################################################
0011 #####   Definition    #########################################
0012 ############################################################ */
0013 struct Span {
0014     Span() : Span(0,0)
0015     {
0016     }
0017     Span(int mn, int mx)
0018     {
0019         min = mn;
0020         max = mx;
0021     }
0022     int min;
0023     int max;
0024 };
0025 
0026 typedef std::vector<int> Lines;
0027 typedef std::vector<Span> Spans;
0028 
0029 /* ############################################################
0030 #####   KBlocksAIPlanner    ###################################
0031 ############################################################ */
0032 KBlocksAIPlanner::KBlocksAIPlanner(KBlocksField *p) : PlannerInterface(p)
0033 {
0034     mNextPieceValues.clear();
0035 }
0036 
0037 KBlocksAIPlanner::~KBlocksAIPlanner()
0038 {
0039     mNextPieceValues.clear();
0040 }
0041 
0042 int KBlocksAIPlanner::process(KBlocks_PieceType_Detail pieceValue)
0043 {
0044     // board size
0045     int w = mpField->getWidth();
0046     int h = mpField->getHeight();
0047     // piece bound
0048     Spans p_Col_Height = Spans(w);
0049     // board rect
0050     Lines b_Col_maxHeight = Lines(w);
0051 
0052     // board info - max height per column
0053     for (int x = 0; x < w; x++) {
0054         int y = 0;
0055         for (y = 0; y < h; y++) {
0056             if (mpField->getCell(x, y)) {
0057                 break;
0058             }
0059         }
0060         b_Col_maxHeight[x] = y;
0061     }
0062 
0063     // init next_states list
0064     mNextPieceValues.clear();
0065 
0066     // init piece state
0067     KBlocksPiece piece;
0068     piece.fromValue(pieceValue);
0069 
0070     int loopCount = piece.getRotationCount();
0071     // scan all possible rotation
0072     for (int rotation = 0; rotation < loopCount; rotation++) {
0073         // piece info - min/max height per column
0074         piece.setRotation(rotation);
0075 
0076         // scan all possible x position - put piece on board
0077         for (int x = 0; x < w; x++) {
0078             bool invalidPos = false;
0079             piece.setPosX(x);
0080             piece.setPosY(0);
0081 
0082             // init
0083             for (int i = 0; i < w; i++) {
0084                 p_Col_Height[i] = Span(h, -1);
0085             }
0086             for (int i = 0; i < KBlocksPiece_CellCount; i++) {
0087                 int cx = piece.getCellPosX(i);
0088                 int cy = piece.getCellPosY(i);
0089                 if (cx < 0 || cx >= w || mpField->getCell(cx, cy)) {
0090                     invalidPos = true;
0091                     break;
0092                 }
0093                 if (p_Col_Height[cx].min > cy) {
0094                     p_Col_Height[cx].min = cy;
0095                 }
0096                 if (p_Col_Height[cx].max < cy) {
0097                     p_Col_Height[cx].max = cy;
0098                 }
0099             }
0100             if (invalidPos) {
0101                 continue;
0102             }
0103 
0104             // get response height
0105             int y = h;
0106             for (int px = 0; px < w; px++) {
0107                 if (p_Col_Height[px].min == h) {
0108                     continue;
0109                 }
0110                 int dy = b_Col_maxHeight[px] - 1 - p_Col_Height[px].max;
0111                 if (dy < y) {
0112                     y = dy;
0113                 }
0114             }
0115 
0116             if ((y < 0) || (y >= h)) {
0117                 continue;
0118             }
0119 
0120             // state
0121             piece.setPosY(y);
0122             // insert to list
0123             mNextPieceValues.push_back(piece);
0124         }
0125     }
0126 
0127     return (int)(mNextPieceValues.size());
0128 }
0129 
0130 bool KBlocksAIPlanner::getNextBoardStatus(int index, KBlocksField *field)
0131 {
0132     KBlocksPiece *piece = new KBlocksPiece();
0133 
0134     if (!getNextPieceState(index, piece)) {
0135         delete field;
0136         field = nullptr;
0137         delete piece;
0138         return false;
0139     }
0140 
0141     field->copy(mpField);
0142 
0143     for (int i = 0; i < KBlocksPiece_CellCount; i++) {
0144         field->setCell(piece->getCellPosX(i), piece->getCellPosY(i), true);
0145     }
0146     int maxLines = field->getHeight();
0147     for (int i = 0; i < maxLines; i++) {
0148         if (field->checkFilledLine(i)) {
0149             field->removeFilledLine(i);
0150         }
0151     }
0152 
0153     delete piece;
0154 
0155     return true;
0156 }
0157 
0158 bool KBlocksAIPlanner::getNextPieceState(int index, KBlocksPiece *piece)
0159 {
0160     if ((index >= (int)mNextPieceValues.size()) || (index < 0)) {
0161         return false;
0162     }
0163     piece->copy(&mNextPieceValues[index]);
0164     return true;
0165 }
0166 
0167 int KBlocksAIPlanner::count()
0168 {
0169     return mNextPieceValues.size();
0170 }