📄 stonehandler.cpp
字号:
/** stonehandler.cpp*/#include "stonehandler.h"#include "boardhandler.h"#include "group.h"#include "board.h"#include "imagehandler.h"#include <stdlib.h>StoneHandler::StoneHandler(BoardHandler *bh): boardHandler(bh){ CHECK_PTR(boardHandler); stones = new QIntDict<Stone>(367); // prime number larger than 361 (19*19) // TODO: Dynamic for different board size? stones->setAutoDelete(TRUE); groups = new QPtrList<Group>; groups->setAutoDelete(TRUE); workingOnNewMove = false;}StoneHandler::~StoneHandler(){ clearData(); delete stones; delete groups;}void StoneHandler::clearData(){ workingOnNewMove = false; stones->clear(); groups->clear();}bool StoneHandler::addStone(Stone *stone, bool toAdd, bool doCheck, Matrix *m, bool koStone){// CHECK_PTR(stone);// CHECK_PTR(m); if (toAdd) stones->insert(Matrix::coordsToKey(stone->posX(), stone->posY()), stone); if (doCheck) return checkPosition(stone, m, koStone); return true;}bool StoneHandler::removeStone(int x, int y, bool hide){ if (!hasStone(x, y)) return false; if (!hide) { // We delete the killed stones only if we want to update the board (i.e. : not if we are browsing the game) if (boardHandler->getDisplay_incoming_move()) //SL added eb 9 if (!stones->remove(Matrix::coordsToKey(x, y))) { qWarning(" *** Key for stone %d, %d not found! ***", x, y); return false; } } else { Stone *s; if ((s = stones->find(Matrix::coordsToKey(x, y))) == NULL) { qWarning(" *** Key for stone %d, %d not found! ***", x, y); return false; } s->hide(); } return true;}// 0 : no stone// -1 : hidden// 1 : shownint StoneHandler::hasStone(int x, int y){ Stone *s; if ((s = stones->find(Matrix::coordsToKey(x, y))) == NULL) return 0; if (s->visible()) return 1; return -1;}//bool StoneHandler::checkPosition(Stone *stone)bool StoneHandler::checkPosition(Stone *stone, Matrix *m, bool koStone){ //CHECK_PTR(stone); // CHECK_PTR(m); // SL added eb 8 if (!stone->visible()) return true; Group *active = NULL; // No groups existing? Create one. if (groups->isEmpty()) { Group *g = assembleGroup(stone,m); CHECK_PTR(g); groups->append(g); active = g; } // We already have one or more groups. else { bool flag = false; Group *tmp; for (unsigned int i=0; i<groups->count(); i++) { tmp = groups->at(i); //CHECK_PTR(tmp); // Check if the added stone is attached to an existing group. // If yes, update this group and replace the old one. // If the stone is attached to two groups, remove the second group. // This happens if the added stone connects two groups. if (tmp->isAttachedTo(stone)) { // Group attached to stone if (!flag) { if (!groups->remove(i)) qFatal("StoneHandler::checkPosition(Stone *stone):" "Oops, removing an attached group failed."); active = assembleGroup(stone,m); groups->insert(i, active); flag = true; } // Groups connected, remove one else { if (active != NULL && active == groups->at(i)) active = tmp; if (!groups->remove(i)) qFatal("StoneHandler::checkPosition(Stone *stone): " "Oops, removing a connected group failed."); i--; } } } // The added stone isnt attached to an existing group. Create a new group. if (!flag) { Group *g = assembleGroup(stone,m); CHECK_PTR(g); groups->append(g); active = g; } } // active->debug(); // Now we have to sort the active group as last in the groups QPtrList, // so if this one is out of liberties, we beep and abort the operation. // This prevents suicide moves. groups->append(groups->take(groups->findRef(active))); // Check the liberties of every group. If a group has zero liberties, remove it. for (unsigned int i=0; i<groups->count(); i++) { Group *tmp = groups->at(i); //CHECK_PTR(tmp); tmp->setLiberties(countLiberties(tmp, m)); //SL added eb 8 // qDebug("Group #%d with %d liberties:", i, tmp->getLiberties()); // tmp->debug(); // Oops, zero liberties. if (tmp->getLiberties() == 0) { // Suicide move? if (tmp == active) { if (active->count() == 1) { groups->remove(i); removeStone(stone->posX(), stone->posY(), false); } return false; } //was it a forbidden ko move ? if ((tmp->count() == 1) && koStone && ((countLiberties(active, m) == 0))) { active->debug(); groups->remove(groups->findRef(active)); removeStone(stone->posX(), stone->posY(), false); return false ; } int stoneCounter = 0; // Erase the stones of this group from the stones table. QListIterator<Stone> it(*tmp); for (; it.current(); ++it) { Stone *s = it.current(); CHECK_PTR(s); if (workingOnNewMove) boardHandler->updateCurrentMatrix(stoneNone, s->posX(), s->posY()); removeStone(s->posX(), s->posY()); stoneCounter ++; } // Remove the group from the groups list. // qDebug("Oops, a group got killed. Removing killed group #%d", i); if (tmp == active) active = NULL; if (!groups->remove(i)) qFatal("StoneHandler::checkPosition(Stone *stone): " "Oops, removing a killed group failed."); i--; // Tell the boardhandler about the captures boardHandler->setCaptures(stone->getColor(), stoneCounter); } } return true;}Group* StoneHandler::assembleGroup(Stone *stone, Matrix *m){ if (stones->isEmpty()) qFatal("StoneHandler::assembleGroup(Stone *stone): No stones on the board!"); Group *group = new Group(); CHECK_PTR(group); // CHECK_PTR(stone);// CHECK_PTR(m); //SL added eb 8 group->append(stone); unsigned int mark = 0; // Walk through the horizontal and vertical directions and assemble the // attached stones to this group. while (mark < group->count()) { stone = group->at(mark); // we use preferably the matrix if ((m==NULL && stone->visible())|| (m!= NULL || m->at(stone->posX() - 1, stone->posY() - 1) != stoneNone )) { int stoneX = stone->posX(), stoneY = stone->posY(); StoneColor col = stone->getColor(); // North group = checkNeighbour(stoneX, stoneY-1, col, group,m); //SL added eb 8 // West group = checkNeighbour(stoneX-1, stoneY, col, group,m); //SL added eb 8 // South group = checkNeighbour(stoneX, stoneY+1, col, group,m); //SL added eb 8 // East group = checkNeighbour(stoneX+1, stoneY, col, group,m); //SL added eb 8 } mark ++; } return group;}Group* StoneHandler::checkNeighbour(int x, int y, StoneColor color, Group *group, Matrix *m) //SL added eb 8{// CHECK_PTR(group);// CHECK_PTR(m); //added eb 8 bool visible = false ; int size = boardHandler->board->getBoardSize(); //end add eb 8 Stone *tmp = stones->find(Matrix::coordsToKey(x, y)); // Okay, this is dirty and synthetic : // Because we use this function where the matrix can be NULL, we need to check this // Furthermore, since this has been added after the first code, we keep the 'stone->visible' test where one should only use the 'matrix' code if (m != NULL && x-1 >= 0 && x-1 < size && y-1 >= 0 && y-1 < size) //SL added eb 8 visible = (m->at(x - 1, y - 1) != stoneNone); //SL added eb 9 We do this in order not to pass a null matrix to the matrix->at function (seen in handicap games) // again we priviledge matrix over stone visibility (we might be browsing a game) if (tmp != NULL && tmp->getColor() == color && (tmp->visible()|| visible)) //SL added eb 8 { if (!group->contains(tmp)) { group->append(tmp); tmp->checked = true; } } return group;}int StoneHandler::countLiberties(Group *group, Matrix *m) //SL added eb 8{// CHECK_PTR(group);// CHECK_PTR(m); // SL added eb 8 int liberties = 0; QValueList<int> libCounted; // Walk through the horizontal and vertial directions, counting the // liberties of this group. for (unsigned int i=0; i<group->count(); i++) { Stone *tmp = group->at(i); //CHECK_PTR(tmp); int x = tmp->posX(), y = tmp->posY(); // North checkNeighbourLiberty(x, y-1, libCounted, liberties,m); //SL added eb 8 // West checkNeighbourLiberty(x-1, y, libCounted, liberties,m); //SL added eb 8 // South checkNeighbourLiberty(x, y+1, libCounted, liberties,m); //SL added eb 8 // East checkNeighbourLiberty(x+1, y, libCounted, liberties,m); //SL added eb 8 } return liberties;}void StoneHandler::checkNeighbourLiberty(int x, int y, QValueList<int> &libCounted, int &liberties, Matrix *m) //SL added eb 8{ if (!x || !y) return; Stone *s;// CHECK_PTR(m); // SL added eb 8 if (m==NULL) //added eb 8 -> we don't have a matrix passed here, so we check on the board { if (x <= boardHandler->board->getBoardSize() && y <= boardHandler->board->getBoardSize() && x >= 0 && y >= 0 && !libCounted.contains(100*x + y) && ((s = stones->find(Matrix::coordsToKey(x, y))) == NULL || !s->visible())) { libCounted.append(100*x + y); liberties ++; } } else { if (x <= boardHandler->board->getBoardSize() && y <= boardHandler->board->getBoardSize() && x >= 0 && y >= 0 && !libCounted.contains(100*x + y) && (m->at(x - 1, y - 1) == stoneNone )) // ?? check stoneErase ? { libCounted.append(100*x + y); liberties ++; } // end add eb 8 }}int StoneHandler::countLibertiesOnMatrix(Group *group, Matrix *m) { CHECK_PTR(group); CHECK_PTR(m); int liberties = 0; QValueList<int> libCounted; // Walk through the horizontal and vertial directions, counting the // liberties of this group.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -