summaryrefslogtreecommitdiffstats
path: root/ksnake/snake.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ksnake/snake.cpp')
-rw-r--r--ksnake/snake.cpp557
1 files changed, 557 insertions, 0 deletions
diff --git a/ksnake/snake.cpp b/ksnake/snake.cpp
new file mode 100644
index 00000000..33b3f027
--- /dev/null
+++ b/ksnake/snake.cpp
@@ -0,0 +1,557 @@
+/**
+ * Copyright Michel Filippi <mfilippi@sade.rhein-main.de>
+ * Robert Williams
+ * Andrew Chant <andrew.chant@utoronto.ca>
+ * André Luiz dos Santos <andre@netvision.com.br>
+ * Benjamin Meyer <ben+ksnake@meyerhome.net>
+ *
+ * This file is part of the ksnake package
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <qwidget.h>
+
+#include "snake.h"
+
+int opposite[4] = { S, N , W, E };
+
+int emptySq[4][4]={
+ { N, E, W, N },
+ { S, W, E, S },
+ { E, N, S, E },
+ { W, S, N, W }
+};
+
+Snake::Snake(Board *b, PixServer *p, Gate g, PixMap x)
+{
+ list.setAutoDelete( true );
+ pixServer = p;
+ board = b;
+ gate = g;
+ pixmap = x;
+ random.setSeed(0);
+}
+
+void Snake::updateSamy()
+{
+ int x = tail();
+ while ( x > 0) {
+ *list.at(x) = *list.at(x-1);
+ --x;
+ }
+}
+
+void Snake::zero()
+{
+ for ( Samy *sam = list.first(); sam != 0; sam = list.next() ) {
+ board->set(sam->index, empty);
+ pixServer->erase(sam->index);
+ }
+}
+
+void Snake::appendSamy()
+{
+ Samy *sam = new Samy;
+ list.append(sam);
+
+ updateSamy();
+ grow--;
+}
+
+void Snake::reset(int index, int border)
+{
+ Samy *sam = list.first();
+
+ switch (border) {
+ case N:
+ sam->pixmap = (tail() == 0 ? HtailUp : HeadUp);
+ break;
+ case S:
+ sam->pixmap = (tail() == 0 ? HtailDown : HeadDown);
+ break;
+ case E:
+ sam->pixmap = (tail() == 0 ? HtailRight : HeadRight);
+ break;
+ case W:
+ sam->pixmap = (tail() == 0 ? HtailLeft : HeadLeft);
+ break;
+ }
+
+ sam->index = index;
+ sam->direction = border;
+
+ if (tail() > 1) {
+
+ sam = list.next();
+
+ if (sam->direction == border) {
+ if (border == N || border == S)
+ sam->pixmap = BodyVt;
+ else
+ sam->pixmap = BodyHz;
+ }
+ else {
+ if (border == W && sam->direction == S
+ || border == N && sam->direction == E)
+ sam->pixmap = AngleNw;
+ if (border == E && sam->direction == S
+ || border == N && sam->direction == W)
+ sam->pixmap = AngleNe;
+ if(border == W && sam->direction == N
+ || border == S && sam->direction == E)
+ sam->pixmap = AngleSw;
+ if(border == E && sam->direction == N
+ || border == S && sam->direction == W)
+ sam->pixmap = AngleSe;
+ }
+
+
+ } //end if (tail() > 1)
+
+ if (tail() > 0) {
+
+ sam = list.last();
+
+ switch (list.at(tail()-1)->direction) {
+ case N:
+ sam->pixmap = TailUp;
+ break;
+ case S:
+ sam->pixmap = TailDown;
+ break;
+ case E:
+ sam->pixmap = TailRight;
+ break;
+ case W:
+ sam->pixmap = TailLeft;
+ break;
+ }
+ }
+}
+
+void Snake::repaint( bool dirty)
+{
+ int x = 0;
+ for ( Samy *sam = list.first(); sam != 0; sam = list.next(), x++) {
+ if (sam->index != OUT ) {
+ if(!dirty && x > 1 && x < tail())
+ continue;
+ pixServer->draw(sam->index, pixmap, sam->pixmap);
+ }
+ }
+ if (!growing() && hold != OUT && hold != gate) {
+ pixServer->erase(hold);
+ }
+}
+
+
+CompuSnake::CompuSnake( Board *b, PixServer *p)
+ : Snake( b, p, NORTH_GATE, CompuSnakePix )
+{
+ init();
+}
+
+bool CompuSnake::init()
+{
+ if( !list.isEmpty()) {
+ list.clear();
+ }
+
+ int index = NORTH_GATE;
+ int length = 12;
+ grow = 0;
+ hold = OUT;
+
+ if ( !board->isBrick(gate) ) return false;
+
+ Samy *sam;
+ for ( int x = 0; x < length; x++) {
+ board->set(index, snake);
+ sam = new Samy;
+ sam->direction = S;
+ sam->index = index;
+ sam->pixmap = (x == 0 ? HeadDown : BodyVt);
+ list.append(sam);
+ index = -1;
+ }
+ return true;
+}
+
+bool CompuSnake::permission()
+{
+ if( list.isEmpty() ){
+
+ if ( hold != OUT) {
+ emit killed();
+ hold = OUT;
+ }
+
+ if(board->isBrick(gate)){
+ static int skip = 12;
+ if (skip < 12) {
+ skip++;
+ return false;
+ } else {
+ skip = 0;
+ return init();
+ }
+ }
+ else return false;
+ }
+ else return true;
+}
+
+void CompuSnake::nextMove()
+{
+ if (!permission())
+ return;
+
+ Samy *sam = list.first();
+ int index = sam->index;
+ int dir = sam->direction;
+ static bool varies = false;
+
+
+ bool found = false;
+
+ for ( int x = 0; x < 4 ; x++) {
+ int next = board->getNext(x, sam->index);
+ if (board->isApple(next)){
+ index = next;
+ dir = x;
+ found = true;
+ grow+=6;
+ emit score(false, index);
+ break;
+ }
+ }
+
+ if(!found)
+ for ( int x = 0; x < 4 ; x++) {
+ int sq = emptySq[sam->direction][x];
+ if (varies && (x > 0 && x < 3))
+ sq = opposite[sq];
+ int next = board->getNext(sq, sam->index);
+ if (findEmpty(next, x)) {
+ index = next;
+ dir = sq;
+ found = true;
+ break;
+ }
+ }
+ varies = !varies;
+
+ if(!found) {
+ hold = list.last()->index;
+ if (board->isSnake(hold)) board->set(hold, empty);
+ removeSamy();
+ }
+ else
+ if(growing())
+ appendSamy();
+ else
+ if (!growing() && found) {
+ hold = list.last()->index;
+ if (board->isSnake(hold)) board->set(hold, empty);
+ updateSamy();
+ }
+
+ if( !list.isEmpty()) {
+ board->set(index, snake);
+ reset(index, dir);
+ }
+
+ if ( hold == gate)
+ out();
+}
+
+void KillerCompuSnake::nextMove()
+{
+ if (!permission()) return;
+
+ Samy *sam = list.first();
+ int index = sam->index;
+ int dir = sam->direction;
+ static bool varies = false;
+
+
+ bool found = false;
+
+ if(!found) {
+ int sn = board->samyHeadIndex();
+ if(sn != -1 && board->isHead(sn)) {
+ int nextSq = board->getNextCloseTo(index, sn, false, lastIndex);
+ if(nextSq != -1) {
+ dir = board->direction(index, nextSq);
+ index = nextSq;
+ found = true;
+ }
+ }
+ }
+
+ if(!found)
+ for ( int x = 0; x < 4 ; x++) {
+ int sq = emptySq[sam->direction][x];
+ if (varies && (x > 0 && x < 3))
+ sq = opposite[sq];
+ int next = board->getNext(sq, sam->index);
+ if (findEmpty(next, x)) {
+ index = next;
+ dir = sq;
+ found = true;
+ break;
+ }
+ }
+ varies = !varies;
+
+ if(!found) {
+ hold = list.last()->index;
+ if (board->isSnake(hold)) board->set(hold, empty);
+ removeSamy();
+ }
+ else {
+ lastIndex = index;
+
+ if(growing())
+ appendSamy();
+ else
+ if (!growing() && found) {
+ hold = list.last()->index;
+ if (board->isSnake(hold)) board->set(hold, empty);
+ updateSamy();
+ }
+ }
+
+ if( !list.isEmpty()) {
+ board->set(index, snake);
+ reset(index, dir);
+ }
+
+ if ( hold == gate)
+ out();
+}
+
+void EaterCompuSnake::nextMove()
+{
+ if (!permission()) return;
+
+ Samy *sam = list.first();
+ int index = sam->index;
+ int dir = sam->direction;
+ static bool varies = false;
+
+
+ bool found = false;
+
+ for ( int x = 0; x < 4 ; x++) {
+ int next = board->getNext(x, sam->index);
+ if (board->isApple(next)){
+ index = next;
+ dir = x;
+ found = true;
+ grow+=6;
+ emit score(false, index);
+ break;
+ }
+ }
+
+ if(!found) {
+ int sn;
+ bool apple = false;
+ for(sn = board->count() - 1; sn > 0; sn --) {
+ if(board->isApple(sn)) {
+ apple = true;
+ int nextSq = board->getNextCloseTo(index, sn, false);
+ if(nextSq != -1) {
+ dir = board->direction(index, nextSq);
+ index = nextSq;
+ found = true;
+ break;
+ }
+ }
+ }
+ if(!found && !apple) {
+ // No more apples, move snake to gate.
+ int nextSq = board->getNextCloseTo(index, gate, false, lastIndex);
+ if(nextSq != -1) {
+ dir = board->direction(index, nextSq);
+ index = nextSq;
+ found = true;
+ }
+ }
+ }
+
+ if(!found)
+ for ( int x = 0; x < 4 ; x++) {
+ int sq = emptySq[sam->direction][x];
+ if (varies && (x > 0 && x < 3))
+ sq = opposite[sq];
+ int next = board->getNext(sq, sam->index);
+ if (findEmpty(next, x)) {
+ index = next;
+ dir = sq;
+ found = true;
+ break;
+ }
+ }
+ varies = !varies;
+
+ if(!found) {
+ hold = list.last()->index;
+ if (board->isSnake(hold)) board->set(hold, empty);
+ removeSamy();
+ }
+ else {
+ lastIndex = index;
+
+ if(growing())
+ appendSamy();
+ else
+ if (!growing() && found) {
+ hold = list.last()->index;
+ if (board->isSnake(hold)) board->set(hold, empty);
+ updateSamy();
+ }
+ }
+
+ if( !list.isEmpty()) {
+ board->set(index, snake);
+ reset(index, dir);
+ }
+
+ if ( hold == gate)
+ out();
+}
+
+bool CompuSnake::findEmpty(int i, int it)
+{
+ bool found = false;
+ bool change = false;
+ static int s_random = random.getLong(BoardWidth/2);
+ static int moves = 0;
+
+ if (moves > s_random) {
+ s_random = random.getLong(BoardWidth/2);
+ moves = 0;
+ change = true;
+ }
+
+ found = ( ( board->isEmpty(i) && it > 0)
+ || ( board->isEmpty(i) && !change && it == 0) );
+
+ moves++;
+ change = false;
+ return found;
+}
+
+void CompuSnake::removeSamy()
+{
+ list.remove();
+ grow = 0;
+}
+
+void CompuSnake::out()
+{
+ emit closeGate( gate );
+
+ if( list.isEmpty() )
+ return;
+
+ if(list.first()->index == OUT) {
+ emit restartTimer();
+ list.clear();
+ }
+}
+
+SamySnake::SamySnake( Board *b, PixServer *p)
+ : Snake( b, p, SOUTH_GATE, SamyPix )
+{
+
+}
+
+void SamySnake::init()
+{
+ if( !list.isEmpty()) {
+ list.clear();
+ }
+ Samy *sam;
+
+ int index = SOUTH_GATE;
+ int length = 12;
+ grow = 0;
+ hold = 0;
+
+ for ( int x = 0; x < length; x++) {
+ board->set(index, head);
+ sam = new Samy;
+ sam->direction = N;
+ sam->index = index;
+ sam->pixmap = (x == 0 ? HeadUp : BodyVt);
+ list.append(sam);
+ index = -1;
+ }
+}
+
+samyState SamySnake::nextMove(int direction)
+{
+ Samy *sam = list.first();
+
+ if(!board->isHead(sam->index) && sam->index != OUT)
+ return ko;
+
+ if ( direction == opposite[sam->direction])
+ direction = sam->direction;
+
+ if(sam->index == gate || sam->index == OUT )
+ direction = N;
+
+ if (sam->index == NORTH_GATE) {
+ emit goingOut();
+ direction = N;
+ }
+
+ int index = board->getNext(direction, sam->index);
+
+ if (board->isApple(index)) {
+ grow+=6;
+ emit score(true, index);
+ }
+ else if (!board->isEmpty(index))
+ return ko;
+
+ if(growing())
+ appendSamy();
+ else {
+ hold = list.last()->index;
+ board->set(hold, empty);
+ updateSamy();
+ }
+
+ board->set(sam->index, snake);
+ reset(index, direction);
+ board->set(index, head);
+
+ if ( hold == gate)
+ emit closeGate( gate );
+ else if ( hold == NORTH_GATE)
+ return out;
+
+ return ok;
+}
+
+#include "snake.moc"
+