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 }