From 60a1f5d7d167f1ba35a7a1c1904f309f8ec2b7d6 Mon Sep 17 00:00:00 2001 From: Max-Wilhelm Bruker Date: Sun, 20 Jan 2013 16:40:15 +0100 Subject: [PATCH] Server_CardZone::getFreeGridColumn() now runs in O(log n), which should remove the performance bottleneck when processing insertCard(x = -1) commands on a large zone, e.g. createToken --- common/server_cardzone.cpp | 102 +++++++++++++++++++++++++------------ common/server_cardzone.h | 4 ++ common/server_player.cpp | 4 +- 3 files changed, 76 insertions(+), 34 deletions(-) diff --git a/common/server_cardzone.cpp b/common/server_cardzone.cpp index 00c86991..018abae8 100644 --- a/common/server_cardzone.cpp +++ b/common/server_cardzone.cpp @@ -51,12 +51,59 @@ void Server_CardZone::shuffle() playersWithWritePermission.clear(); } +void Server_CardZone::removeCardFromCoordMap(Server_Card *card, int oldX, int oldY) +{ + if (oldX < 0) + return; + + const int baseX = (oldX / 3) * 3; + QMap &coordMap = coordinateMap[oldY]; + + if (coordMap.contains(baseX) && coordMap.contains(baseX + 1) && coordMap.contains(baseX + 2)) + // If the removal of this card has opened up a previously full pile... + freePilesMap[oldY].insert(coordMap.value(baseX)->getName(), baseX); + + coordMap.remove(oldX); + + if (!(coordMap.contains(baseX) && coordMap.value(baseX)->getName() == card->getName()) && !(coordMap.contains(baseX + 1) && coordMap.value(baseX + 1)->getName() == card->getName()) && !(coordMap.contains(baseX + 2) && coordMap.value(baseX + 2)->getName() == card->getName())) + // If this card was the last one with this name... + freePilesMap[oldY].remove(card->getName(), baseX); + + if (!coordMap.contains(baseX) && !coordMap.contains(baseX + 1) && !coordMap.contains(baseX + 2)) { + // If the removal of this card has freed a whole pile, i.e. it was the last card in it... + if (baseX < freeSpaceMap[oldY]) + freeSpaceMap[oldY] = baseX; + } +} + +void Server_CardZone::insertCardIntoCoordMap(Server_Card *card, int x, int y) +{ + if (x < 0) + return; + + coordinateMap[y].insert(x, card); + if (!(x % 3)) { + if (!freePilesMap[y].contains(card->getName(), x) && card->getAttachedCards().isEmpty()) + freePilesMap[y].insert(card->getName(), x); + if (freeSpaceMap[y] == x) { + int nextFreeX = x; + do { + nextFreeX += 3; + } while (coordinateMap[y].contains(nextFreeX) || coordinateMap[y].contains(nextFreeX + 1) || coordinateMap[y].contains(nextFreeX + 2)); + freeSpaceMap[y] = nextFreeX; + } + } else if (!((x - 2) % 3)) { + const int baseX = (x / 3) * 3; + freePilesMap[y].remove(coordinateMap[y].value(baseX)->getName(), baseX); + } +} + int Server_CardZone::removeCard(Server_Card *card) { int index = cards.indexOf(card); cards.removeAt(index); if (has_coords) - coordinateMap[card->getY()].remove(card->getX()); + removeCardFromCoordMap(card, card->getX(), card->getY()); card->setZone(0); return index; @@ -95,26 +142,18 @@ Server_Card *Server_CardZone::getCard(int id, int *position, bool remove) int Server_CardZone::getFreeGridColumn(int x, int y, const QString &cardName) const { const QMap &coordMap = coordinateMap.value(y); - int resultX = 0; if (x == -1) { - QMapIterator cardIterator(coordMap); - while (cardIterator.hasNext()) { - cardIterator.next(); - const int cardX = cardIterator.key(); - if (cardX % 3) - continue; - Server_Card *card = cardIterator.value(); - if (card->getName() == cardName) { - if (!card->getAttachedCards().isEmpty()) - continue; - if (!coordMap.contains(cardX + 1)) - return cardX + 1; - if (!coordMap.contains(cardX + 2)) - return cardX + 2; - } + if (freePilesMap[y].contains(cardName)) { + x = (freePilesMap[y].value(cardName) / 3) * 3; + if (!coordMap.contains(x)) + return x; + else if (!coordMap.contains(x + 1)) + return x + 1; + else + return x + 2; } - } else if (x == -2) { - } else { + } else if (x >= 0) { + int resultX = 0; x = (x / 3) * 3; if (!coordMap.contains(x)) resultX = x; @@ -129,13 +168,14 @@ int Server_CardZone::getFreeGridColumn(int x, int y, const QString &cardName) co resultX = x; x = -1; } + if (x < 0) + while (coordMap.contains(resultX)) + resultX += 3; + + return resultX; } - if (x < 0) - while (coordMap.contains(resultX)) - resultX += 3; - - return resultX; + return freeSpaceMap[y]; } bool Server_CardZone::isColumnStacked(int x, int y) const @@ -156,14 +196,10 @@ bool Server_CardZone::isColumnEmpty(int x, int y) const void Server_CardZone::moveCardInRow(GameEventStorage &ges, Server_Card *card, int x, int y) { - coordinateMap[y].remove(card->getX()); - CardToMove *cardToMove = new CardToMove; cardToMove->set_card_id(card->getId()); player->moveCard(ges, this, QList() << cardToMove, this, x, y, false, false); delete cardToMove; - - coordinateMap[y].insert(x, card); } void Server_CardZone::fixFreeSpaces(GameEventStorage &ges) @@ -201,9 +237,8 @@ void Server_CardZone::updateCardCoordinates(Server_Card *card, int oldX, int old return; if (oldX != -1) - coordinateMap[oldY].remove(oldX); - if (card->getX() != -1) - coordinateMap[card->getY()].insert(card->getX(), card); + removeCardFromCoordMap(card, oldX, oldY); + insertCardIntoCoordMap(card, card->getX(), card->getY()); } void Server_CardZone::insertCard(Server_Card *card, int x, int y) @@ -211,8 +246,7 @@ void Server_CardZone::insertCard(Server_Card *card, int x, int y) if (hasCoords()) { card->setCoords(x, y); cards.append(card); - if (x != -1) - coordinateMap[y].insert(x, card); + insertCardIntoCoordMap(card, x, y); } else { card->setCoords(0, 0); if (x == -1) @@ -229,6 +263,8 @@ void Server_CardZone::clear() delete cards.at(i); cards.clear(); coordinateMap.clear(); + freePilesMap.clear(); + freeSpaceMap.clear(); playersWithWritePermission.clear(); } diff --git a/common/server_cardzone.h b/common/server_cardzone.h index 45c75adf..1eeb9008 100644 --- a/common/server_cardzone.h +++ b/common/server_cardzone.h @@ -42,6 +42,10 @@ private: bool alwaysRevealTopCard; QList cards; QMap > coordinateMap; // y -> (x -> card) + QMap > freePilesMap; // y -> (cardName -> x) + QMap freeSpaceMap; // y -> x + void removeCardFromCoordMap(Server_Card *card, int oldX, int oldY); + void insertCardIntoCoordMap(Server_Card *card, int x, int y); public: Server_CardZone(Server_Player *_player, const QString &_name, bool _has_coords, ServerInfo_Zone::ZoneType _type); ~Server_CardZone(); diff --git a/common/server_player.cpp b/common/server_player.cpp index 5732ac79..26a815b3 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -552,7 +552,7 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges, Server_Car void Server_Player::unattachCard(GameEventStorage &ges, Server_Card *card) { Server_CardZone *zone = card->getZone(); - + Server_Card *parentCard = card->getParentCard(); card->setParentCard(0); Event_AttachCard event; @@ -564,6 +564,8 @@ void Server_Player::unattachCard(GameEventStorage &ges, Server_Card *card) cardToMove->set_card_id(card->getId()); moveCard(ges, zone, QList() << cardToMove, zone, -1, card->getY(), card->getFaceDown()); delete cardToMove; + + parentCard->getZone()->updateCardCoordinates(parentCard, parentCard->getX(), parentCard->getY()); } Response::ResponseCode Server_Player::setCardAttrHelper(GameEventStorage &ges, const QString &zoneName, int cardId, CardAttribute attribute, const QString &attrValue)