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 }