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 "KBlocksAIPlannerExtend.h" 0008 #include "KBlocksAILog.h" 0009 0010 using namespace PlanningPath; 0011 0012 /******************************************************************************** 0013 **** Data Structure - PathNode ************************************************* 0014 ********************************************************************************/ 0015 PathNode::PathNode(KBlocksPiece *piece) 0016 { 0017 parent = nullptr; 0018 next = nullptr; 0019 setContent(piece); 0020 } 0021 0022 PathNode::~PathNode() 0023 { 0024 if (next == nullptr) { 0025 return; 0026 } 0027 next->clear(); 0028 delete next; 0029 } 0030 0031 void PathNode::setContent(KBlocksPiece *piece) 0032 { 0033 content = *piece; 0034 } 0035 0036 KBlocksPiece PathNode::getContent() 0037 { 0038 return content; 0039 } 0040 0041 void PathNode::setParent(PathNode *parent) 0042 { 0043 this->parent = parent; 0044 } 0045 0046 PathNode *PathNode::getParent() 0047 { 0048 return parent; 0049 } 0050 0051 void PathNode::setNext(PathTree *&next) 0052 { 0053 this->next = next; 0054 } 0055 0056 /******************************************************************************* 0057 **** Planner ****************************************************************** 0058 ********************************************************************************/ 0059 KBlocksAIPlannerExtend::KBlocksAIPlannerExtend(KBlocksField *field) : KBlocksAIPlanner(field) 0060 { 0061 mPathTree = new PathTree(); 0062 mPathList = new LeafList(); 0063 } 0064 0065 KBlocksAIPlannerExtend::~KBlocksAIPlannerExtend() 0066 { 0067 mPathTree->clear(); 0068 delete mPathTree; 0069 mPathList->clear(); 0070 delete mPathList; 0071 } 0072 0073 bool KBlocksAIPlannerExtend::getPath(int index, AIPlanner_PieceInfo_Sequence *pseq) 0074 { 0075 if ((mPathList == nullptr) || (index >= (int)mPathList->size())) { 0076 return false; 0077 } 0078 0079 PathNode *node = (*mPathList)[index]; 0080 while (node != nullptr) { 0081 KBlocksPiece piece = node->getContent(); 0082 pseq->push_back(piece); 0083 node = node->getParent(); 0084 } 0085 0086 return true; 0087 } 0088 0089 bool KBlocksAIPlannerExtend::getNextBoardStatus(int index, KBlocksField *field) 0090 { 0091 return getNextBoardStatus(index, field, false); 0092 } 0093 0094 bool KBlocksAIPlannerExtend::getNextBoardStatus(int index, KBlocksField *field, bool first) 0095 { 0096 AIPlanner_PieceInfo_Sequence path = AIPlanner_PieceInfo_Sequence(0); 0097 0098 if (getPath(index, &path) == false) { 0099 delete field; 0100 field = nullptr; 0101 return false; 0102 } 0103 0104 if (first) { 0105 KBlocksPiece firstps = path.back(); 0106 path.clear(); 0107 path.push_back(firstps); 0108 } 0109 0110 field->copy(mpField); 0111 0112 for (int i = (int)path.size() - 1; i >= 0; i--) { 0113 KBlocksPiece *piece = &path[i]; 0114 for (int j = 0; j < KBlocksPiece_CellCount; j++) { 0115 field->setCell(piece->getCellPosX(j), piece->getCellPosY(j), true); 0116 } 0117 int maxLines = field->getHeight(); 0118 for (int i = 0; i < maxLines; i++) { 0119 if (field->checkFilledLine(i)) { 0120 field->removeFilledLine(i); 0121 } 0122 } 0123 } 0124 0125 return true; 0126 } 0127 0128 bool KBlocksAIPlannerExtend::getNextPieceState(int index, KBlocksPiece *piece) 0129 { 0130 if (index >= (int)mPathList->size()) { 0131 return false; 0132 } 0133 PathNode *node = (*mPathList)[index]; 0134 PathNode *last = nullptr; 0135 while (node != nullptr) { 0136 last = node; 0137 node = node->getParent(); 0138 } 0139 if (last == nullptr) { 0140 return false; 0141 } 0142 *piece = last->getContent(); 0143 return true; 0144 } 0145 0146 int KBlocksAIPlannerExtend::count() 0147 { 0148 return mPathList->size(); 0149 } 0150 0151 // get next piece_state 0152 int KBlocksAIPlannerExtend::process(KBlocks_PieceType_Detail pieceValue) 0153 { 0154 AIPlanner_PieceValue_Sequence pseq = AIPlanner_PieceValue_Sequence(0); 0155 pseq.push_front(pieceValue); 0156 return process(pseq); 0157 } 0158 0159 // get next piece_state 0160 int KBlocksAIPlannerExtend::process(const AIPlanner_PieceValue_Sequence &pseq) 0161 { 0162 mPathTree->clear(); 0163 mPathList->clear(); 0164 PathNode *parent = nullptr; 0165 AIPlanner_PieceValue_Sequence tmpPSeq = AIPlanner_PieceValue_Sequence(pseq); 0166 process_nstep_recursive(parent, tmpPSeq, *mPathTree, *mPathList); 0167 return mPathList->size(); 0168 } 0169 0170 void KBlocksAIPlannerExtend::process_nstep_recursive(PlanningPath::PathNode *parent, 0171 AIPlanner_PieceValue_Sequence &pseq, 0172 PlanningPath::PathTree &tree, 0173 PlanningPath::LeafList &leaf) 0174 { 0175 if (pseq.size() == 0) { 0176 return; 0177 } 0178 0179 bool isLeaf = (pseq.size() == 1); 0180 0181 KBlocks_PieceType_Detail first_piece_type = pseq.front(); 0182 pseq.pop_front(); 0183 0184 int n = KBlocksAIPlanner::process(first_piece_type); 0185 for (int i = 0; i < n; i++) { 0186 KBlocksPiece piece; 0187 KBlocksAIPlanner::getNextPieceState(i, &piece); 0188 tree.push_back(PathNode(&piece)); 0189 } 0190 0191 for (int i = 0; i < (int)tree.size(); i++) { 0192 // get next possible piece state 0193 PathNode *_node = &tree[i]; 0194 _node->setParent(parent); 0195 KBlocksPiece _pstate = tree[i].getContent(); 0196 0197 // get current board_status based on current piece state 0198 KBlocksField *_tmpBS = new KBlocksField(mpField); 0199 for (int i = 0; i < KBlocksPiece_CellCount; i++) { 0200 _tmpBS->setCell(_pstate.getCellPosX(i), _pstate.getCellPosY(i), true); 0201 } 0202 // remove the filled lines in current board 0203 int maxLines = _tmpBS->getHeight(); 0204 for (int i = 0; i < maxLines; i++) { 0205 if (_tmpBS->checkFilledLine(i)) { 0206 _tmpBS->removeFilledLine(i); 0207 } 0208 } 0209 0210 // get copy of piece_info_sequence 0211 AIPlanner_PieceValue_Sequence _pseq = AIPlanner_PieceValue_Sequence(pseq); 0212 0213 // get next tree based on _tmpBS and _pseq 0214 KBlocksAIPlannerExtend planner = KBlocksAIPlannerExtend(_tmpBS); 0215 PathTree *_next = new PathTree(); 0216 planner.process_nstep_recursive(_node, _pseq, *_next, leaf); 0217 _node->setNext(_next); 0218 0219 if (isLeaf) { 0220 leaf.push_back(_node); 0221 } 0222 0223 delete _tmpBS; 0224 } 0225 }