summaryrefslogtreecommitdiffstats
path: root/chicken-wranglers/src/ai/matchai.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chicken-wranglers/src/ai/matchai.cpp')
-rw-r--r--chicken-wranglers/src/ai/matchai.cpp408
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;
+}