diff options
Diffstat (limited to 'chicken-wranglers/src/ai/matchai.cpp')
-rw-r--r-- | chicken-wranglers/src/ai/matchai.cpp | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/chicken-wranglers/src/ai/matchai.cpp b/chicken-wranglers/src/ai/matchai.cpp new file mode 100644 index 0000000..1870655 --- /dev/null +++ b/chicken-wranglers/src/ai/matchai.cpp @@ -0,0 +1,408 @@ +/**************************************************************************** +** +** This file is a part of QtChickenWranglers. +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).* +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +** FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +** COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +** BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +** ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +** POSSIBILITY OF SUCH DAMAGE." +** +****************************************************************************/ + + +#include "global.h" + +#include "matchai.h" + +MatchAI::MatchAI(QSize matchCanvasSize) +{ + m_graph = new Graph(matchCanvasSize); +} + +MatchAI::~MatchAI() +{ + m_graph->deleteLater(); +} + +bool MatchAI::addChicken(QPoint position) +{ + Node *chickenNode = m_graph->node(position); + + if (!chickenNode || !chickenNode->isEmpty()) + return false; + + chickenNode->data = Node::Chicken; + chickenNode->chickenCount = 1; + + return true; +} + +Node *MatchAI::addPlayer(QPoint position) +{ + Node *playerNode = m_graph->node(position); + + if (!playerNode || !playerNode->isEmpty()) + return 0; + + Node *hencoop = addHencoop(playerNode); + + if (hencoop) { + playerNode->data = Node::Player; + doUnSafe(playerNode); + } + + return hencoop; +} + +bool MatchAI::toggleLaser(QPoint position, Global::LaserDirection direction) +{ + Node *node = m_graph->node(position); + Node *neighbor; + + if (!node) + return false; + + switch (direction) { + + case Global::LaserUp: + neighbor = m_graph->node(position + QPoint(0, -1)); + if (neighbor) { + if (node->neighbor[Node::Up] != neighbor) { + // Turn off laser + node->neighbor[Node::Up] = neighbor; + neighbor->neighbor[Node::Down] = node; + return false; + } else { + // Turn on laser + node->neighbor[Node::Up] = node; + neighbor->neighbor[Node::Down] = neighbor; + return true; + } + } + break; + + case Global::LaserDown: + neighbor = m_graph->node(position + QPoint(0, 1)); + if (neighbor) { + if (node->neighbor[Node::Down] != neighbor) { + // Turn off laser + node->neighbor[Node::Down] = neighbor; + neighbor->neighbor[Node::Up] = node; + return false; + } else { + // Turn on laser + node->neighbor[Node::Down] = node; + neighbor->neighbor[Node::Up] = neighbor; + return true; + } + } + break; + + case Global::LaserRight: + neighbor = m_graph->node(position + QPoint(1, 0)); + if (neighbor) { + if (node->neighbor[Node::Right] != neighbor) { + // Turn off laser + node->neighbor[Node::Right] = neighbor; + neighbor->neighbor[Node::Left] = node; + return false; + } else { + // Turn on laser + node->neighbor[Node::Right] = node; + neighbor->neighbor[Node::Left] = neighbor; + return true; + } + } + break; + + case Global::LaserLeft: + neighbor = m_graph->node(position + QPoint(-1, 0)); + if (neighbor) { + if (node->neighbor[Node::Left] != neighbor) { + // Turn off laser + node->neighbor[Node::Left] = neighbor; + neighbor->neighbor[Node::Right] = node; + return false; + } else { + // Turn on laser + node->neighbor[Node::Left] = node; + neighbor->neighbor[Node::Right] = neighbor; + return true; + } + } + break; + + default: + return false; + } + + return false; +} + +QPair<QPoint, Global::Direction> MatchAI::moveChicken(QPoint position) +{ + Node *chickenNode = m_graph->node(position); + + if (!chickenNode || !chickenNode->isChicken()) + return QPair<QPoint, Global::Direction>(position, Global::DirectionStop); + + QList<QPair<QPoint, Node::Neighbor> > nextPosList; + Node *neighbor; + if (chickenNode->isSafe() && chickenNode->chickenCount == 1) { + nextPosList.append(QPair<QPoint, Node::Neighbor>(position, Node::Stop)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(position, Node::Stop)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(position, Node::Stop)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(position, Node::Stop)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(position, Node::Stop)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(position, Node::Stop)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(position, Node::Stop)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(position, Node::Stop)); + } + + neighbor = chickenNode->neighbor[Node::Up]; + if (!neighbor->isPlayer() && neighbor->isSafe() && chickenNode != neighbor) { + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Up)); + if (chickenNode->neighbor[Node::Down]->isPlayer()) { + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Up)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Up)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Up)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Up)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Up)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Up)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Up)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Up)); + } + } + + neighbor = chickenNode->neighbor[Node::Down]; + if (!neighbor->isPlayer() && neighbor->isSafe() && chickenNode != neighbor) { + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Down)); + if (chickenNode->neighbor[Node::Up]->isPlayer()) { + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Down)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Down)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Down)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Down)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Down)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Down)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Down)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Down)); + } + } + + neighbor = chickenNode->neighbor[Node::Right]; + if (!neighbor->isPlayer() && neighbor->isSafe() && chickenNode != neighbor) { + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Right)); + if (chickenNode->neighbor[Node::Left]->isPlayer()) { + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Right)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Right)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Right)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Right)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Right)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Right)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Right)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Right)); + } + } + + neighbor = chickenNode->neighbor[Node::Left]; + if (!neighbor->isPlayer() && neighbor->isSafe() && chickenNode != neighbor) { + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Left)); + if (chickenNode->neighbor[Node::Right]->isPlayer()) { + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Left)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Left)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Left)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Left)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Left)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Left)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Left)); + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Left)); + } + } + + if (nextPosList.isEmpty()) { + neighbor = chickenNode->neighbor[Node::Up]; + + if (neighbor->isScape() && neighbor->rank < chickenNode->rank && chickenNode != neighbor) + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Up)); + + neighbor = chickenNode->neighbor[Node::Down]; + if (neighbor->isScape() && neighbor->rank < chickenNode->rank && chickenNode != neighbor) + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Down)); + + neighbor = chickenNode->neighbor[Node::Right]; + if (neighbor->isScape() && neighbor->rank < chickenNode->rank && chickenNode != neighbor) + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Right)); + + neighbor = chickenNode->neighbor[Node::Left]; + if (neighbor->isScape() && neighbor->rank < chickenNode->rank && chickenNode != neighbor) + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Left)); + } + + if (nextPosList.isEmpty()) { + neighbor = chickenNode->neighbor[Node::Up]; + + if (!neighbor->isPlayer() && neighbor->rank < chickenNode->rank && chickenNode != neighbor) + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Up)); + + neighbor = chickenNode->neighbor[Node::Down]; + if (!neighbor->isPlayer() && neighbor->rank < chickenNode->rank && chickenNode != neighbor) + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Down)); + + neighbor = chickenNode->neighbor[Node::Right]; + if (!neighbor->isPlayer() && neighbor->rank < chickenNode->rank && chickenNode != neighbor) + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Right)); + + neighbor = chickenNode->neighbor[Node::Left]; + if (!neighbor->isPlayer() && neighbor->rank < chickenNode->rank && chickenNode != neighbor) + nextPosList.append(QPair<QPoint, Node::Neighbor>(neighbor->pos, Node::Left)); + } + + if (nextPosList.isEmpty()) + return QPair<QPoint, Global::Direction>(position, Global::DirectionStop); + + QPair<QPoint, Node::Neighbor> nextPos = nextPosList.at(qrand() % nextPosList.size()); + neighbor = chickenNode->neighbor[nextPos.second]; + if (neighbor != chickenNode) { + chickenNode->chickenCount -= 1; + if (!chickenNode->chickenCount) + chickenNode->data = Node::Empty; + + neighbor->chickenCount += 1; + + if (neighbor->isHencoop()) + neighbor->emitChickenEntered(); + else + neighbor->data = Node::Chicken; + } + + return QPair<QPoint, Global::Direction>(nextPos.first, + Node::neighborDirection(nextPos.second)); +} + +QPoint MatchAI::movePlayer(QPoint position, Global::Direction direction) +{ + Node *playerNode = m_graph->node(position); + + if (!playerNode || playerNode->data != Node::Player) + return position; + + Node *neighbor = playerNode->neighbor[Node::directionNeighbor(direction)]; + if (neighbor->isEmpty()) { + playerNode->data = Node::Empty; + neighbor->data = Node::Player; + + doSafe(playerNode); + + playerNode->direction = Node::Stop; + neighbor->direction = Node::directionNeighbor(direction); + + doUnSafe(neighbor); + + return neighbor->pos; + } else { + doSafe(playerNode); + playerNode->direction = Node::directionNeighbor(direction); + doUnSafe(playerNode); + } + + return position; +} + +bool MatchAI::isChickenSafe(QPoint position) +{ + Node *chickenNode = m_graph->node(position); + + if (!chickenNode || chickenNode->data != Node::Chicken) + return false; + + return chickenNode->isSafe(); +} + +Node *MatchAI::addHencoop(Node *node) +{ + if (node->neighbor[Node::Right] == node) { + node->rank = 1; + node->neighbor[Node::Right] = new Node(m_graph); + node->neighbor[Node::Right]->data = Node::Hencoop; + node->neighbor[Node::Right]->rank = 4; + node->neighbor[Node::Right]->pos = node->pos + QPoint(1, 0); + return node->neighbor[Node::Right]; + } + + if (node->neighbor[Node::Left] == node) { + node->rank = 1; + node->neighbor[Node::Left] = new Node(m_graph); + node->neighbor[Node::Left]->data = Node::Hencoop; + node->neighbor[Node::Left]->rank = 4; + node->neighbor[Node::Left]->pos = node->pos + QPoint(-1, 0); + return node->neighbor[Node::Left]; + } + + return 0; +} + +void MatchAI::doUnSafe(QPoint position) +{ + Node *playerNode = m_graph->node(position); + + if (!playerNode || !playerNode->isPlayer()) + return; + doUnSafe(playerNode); +} + +void MatchAI::doSafe(QPoint position) +{ + Node *playerNode = m_graph->node(position); + + if (!playerNode || !playerNode->isPlayer()) + return; + doSafe(playerNode); +} + +void MatchAI::doUnSafe(Node *node) +{ + node->neighbor[Node::Up]->rank += 2; + node->neighbor[Node::Down]->rank += 2; + node->neighbor[Node::Right]->rank += 2; + node->neighbor[Node::Left]->rank += 2; + node->neighbor[node->direction]->rank += 4; +} + +void MatchAI::doSafe(Node *node) +{ + node->neighbor[Node::Up]->rank -= 2; + node->neighbor[Node::Down]->rank -= 2; + node->neighbor[Node::Right]->rank -= 2; + node->neighbor[Node::Left]->rank -= 2; + node->neighbor[node->direction]->rank -= 4; +} |