summaryrefslogtreecommitdiffstats
path: root/ksame/StoneField.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitc90c389a8a8d9d8661e9772ec4144c5cf2039f23 (patch)
tree6d8391395bce9eaea4ad78958617edb20c6a7573 /ksame/StoneField.cpp
downloadtdegames-c90c389a8a8d9d8661e9772ec4144c5cf2039f23.tar.gz
tdegames-c90c389a8a8d9d8661e9772ec4144c5cf2039f23.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegames@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'ksame/StoneField.cpp')
-rw-r--r--ksame/StoneField.cpp399
1 files changed, 399 insertions, 0 deletions
diff --git a/ksame/StoneField.cpp b/ksame/StoneField.cpp
new file mode 100644
index 00000000..3862d7fb
--- /dev/null
+++ b/ksame/StoneField.cpp
@@ -0,0 +1,399 @@
+/*
+ * ksame 0.4 - simple Game
+ * Copyright (C) 1997,1998 Marcus Kreutzberger
+ *
+ * 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 program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "StoneField.h"
+#include <kdebug.h>
+#include <assert.h>
+
+StoneFieldState::StoneFieldState(const StoneField &stonefield)
+{
+ field=new unsigned char[stonefield.maxstone];
+ for (int i=0;i<stonefield.maxstone;i++)
+ field[i]=stonefield.field[i].color;
+
+ colors=stonefield.colors;
+ board=stonefield.board;
+ score=stonefield.score;
+ gameover=stonefield.gameover;
+}
+
+StoneFieldState::~StoneFieldState() {
+ delete[] field;
+}
+
+void
+StoneFieldState::restore(StoneField &stonefield) const {
+ for (int i=0;i<stonefield.maxstone;i++) {
+ stonefield.field[i].color=field[i];
+ stonefield.field[i].changed=true;
+ stonefield.field[i].marked=false;
+ }
+
+ stonefield.colors=colors;
+ stonefield.board=board;
+ stonefield.score=score;
+ stonefield.marked=0;
+ stonefield.gameover=gameover;
+}
+
+StoneField::StoneField(int width, int height,
+ int colors, unsigned int board,
+ bool undoenabled)
+{
+ Q_ASSERT(width>0);
+ Q_ASSERT(height>0);
+
+ if (undoenabled) undolist=new QPtrList<StoneFieldState>;
+ else undolist=0;
+
+ sizex=width;
+ sizey=height;
+ maxstone=sizex*sizey;
+ field=new Stone[maxstone];
+ newGame(board,colors);
+ m_gotBonus= false;
+}
+
+StoneField::~StoneField() {
+ delete[] field;
+ delete undolist;
+ kdDebug() << "~StoneField\n" << endl;
+}
+
+int StoneField::count(int color){
+ int c = 0;
+ Stone *stone=field;
+ for (int i=0;i<maxstone;i++,stone++) {
+ if(stone->color == color)
+ c++;
+ }
+ return c;
+}
+
+int
+StoneField::width() const {
+ return sizex;
+}
+
+int
+StoneField::height() const {
+ return sizey;
+}
+
+void
+StoneField::newGame(unsigned int board,int colors) {
+ kdDebug() << "StoneField::newgame board "
+ << board << " colors " << colors << endl;
+ if (colors<1) colors=3;
+ if (colors>7) colors=7;
+ this->colors=colors;
+ this->board=board;
+ reset();
+}
+
+void
+StoneField::reset() {
+ random.setSeed(board);
+
+ Stone *stone=field;
+ for (int i=0;i<maxstone;i++,stone++) {
+ stone->color=1+random.getLong(colors);
+ stone->marked=false;
+ stone->changed=true;
+ }
+
+ gameover=-1;
+ score=0;
+ marked=0;
+
+ if (undolist) {
+ undolist->setAutoDelete(true);
+ undolist->clear();
+ }
+
+ int c[7];
+ int j;
+ for (j=0;j<7;j++) c[j]=0;
+
+ for (j=0,stone=field;j<maxstone;j++,stone++) {
+ c[stone->color]++;
+ }
+ kdDebug() << "red " << c[1] << endl;
+ kdDebug() << "blue " << c[2] << endl;
+ kdDebug() << "yellow " << c[3] << endl;
+ kdDebug() << "green " << c[4] << endl;
+}
+
+int
+StoneField::map(int x,int y) {
+ assert (!(x<0||y<0||x>=sizex||y>=sizey));
+ return x+y*sizex;
+}
+
+int
+StoneField::mark(int x,int y,bool force) {
+ int index=map(x,y);
+
+ if (index<0) {
+ unmark();
+ return 0;
+ }
+
+ if (field[index].marked) return -1;
+ unmark();
+
+ mark(index,field[index].color);
+
+ if (marked==1&&!force) {
+ field[index].marked=false;
+ marked=0;
+ }
+ return marked;
+}
+
+void
+StoneField::mark(int index,unsigned char color) {
+ if ( index<0 || index>=maxstone ) return;
+
+ Stone &stone=field[index];
+
+ if (stone.marked) return;
+
+ if (!stone.color || stone.color!=color) return;
+
+ stone.changed=true;
+ stone.marked=true;
+ marked++;
+
+ // mark left
+ if ((index%sizex)!=0) mark(index-1,color);
+ // mark right
+ if (((index+1)%sizex)!=0) mark(index+1,color);
+ // mark upward
+ if (index>=sizex) mark(index-sizex,color);
+ // mark downward
+ if (index<(sizex-1)*sizey) mark(index+sizex,color);
+}
+
+void
+StoneField::unmark() {
+ if (!marked) return;
+
+ Stone *stone=field;
+ for (int i=0;i<maxstone;i++,stone++) {
+ stone->marked=false;
+ stone->changed=true;
+ }
+ marked=0;
+}
+
+int
+StoneField::remove(int x,int y,bool force) {
+ int index=map(x,y);
+
+ if (index<0) return 0;
+
+ if (!field[index].marked) {
+ mark(x,y,force);
+ }
+
+ if (!marked) return 0;
+
+ // remove a single stone??
+ if (marked==1&&!force) return 0;
+
+ // add current field to undolist
+ if (undolist)
+ undolist->append(new StoneFieldState(*this));
+
+ // increase score
+ if (marked>2)
+ score+=(marked-2)*(marked-2);
+
+ // remove marked stones
+ Stone *stone=field;
+ for (int i=0;i<maxstone;i++,stone++) {
+ if (stone->marked) {
+ stone->color=0;
+ stone->changed=true;
+ stone->marked=false;
+ }
+ }
+ int removed=marked;
+ marked=0;
+
+ for (int col=0;col<sizex;col++) {
+ int i1=col+maxstone-sizex;
+ while ( i1>=0 && field[i1].color ) i1-=sizex;
+ int i2=i1;
+ while (i2>=0) {
+ while ( i2>=0 && !field[i2].color ) i2-=sizex;
+ while ( i2>=0 && field[i2].color ) {
+ field[i1].color=field[i2].color;
+ field[i1].changed=true;
+ field[i2].color=0;
+ field[i2].changed=true;
+ i1-=sizex;
+ i2-=sizex;
+ }
+ }
+ }
+
+ // find the last column that has something
+ int lastcol = sizex;
+ while (lastcol > 0 && !field[map(lastcol-1, sizey-1)].color) {
+ lastcol--;
+ }
+
+ for (int col=0;col<lastcol-1;) {
+ bool empty = true;
+ for (int row = 0; row < sizey; row++)
+ if (field[map(col, row)].color) {
+ empty = false;
+ break;
+ }
+ if (!empty) {
+ col++;
+ continue;
+ }
+ int nextfullcol = col + 1;
+ while (nextfullcol < sizex &&
+ !field[map(nextfullcol, sizey - 1)].color)
+ nextfullcol++;
+
+ if (nextfullcol > sizex - 1)
+ break; // we're ready
+
+ for (int row=0; row < sizey; row++) {
+ int source = map(nextfullcol, row);
+ int dest = map(col, row);
+ field[dest].color=field[source].color;
+ field[dest].changed=true;
+ field[source].color=0;
+ field[source].changed=true;
+ }
+ }
+
+ // add a bonus, if field is empty
+ if (!field[map(0, sizey-1)].color) {
+ score+=1000;
+ m_gotBonus= true;
+ }
+
+ // gameover is undefined
+ gameover=-1;
+ return removed;
+}
+
+bool StoneField::undoPossible() const {
+ return !(!undolist||undolist->isEmpty());
+}
+
+int
+StoneField::undo(int count) {
+ if (!undoPossible())
+ return 0;
+ if (count <= 0)
+ return 0;
+ int undocount=1;
+ StoneFieldState *state=0;
+ undolist->setAutoDelete(true);
+ while (--count>0) {
+ if (undolist->count()==1) break;
+ undolist->removeLast();
+ undocount++;
+ }
+ state=undolist->getLast();
+ Q_ASSERT(state);
+ state->restore(*this);
+ undolist->removeLast();
+ return undocount;
+}
+
+bool
+StoneField::isGameover() const {
+ register int i=maxstone-1;;
+ register unsigned char color;
+
+ if (gameover>=0) return (bool)gameover;
+ // kdDebug() << "-->gameover" << endl;
+
+ while (i>=0) {
+ // kdDebug() << i << " " << field[i].color << endl;
+ // ignore empty fields
+ while ( i>=0 && field[i].color==0 ) i--;
+ // Wenn Stein gefunden,
+ // dann die Nachbarn auf gleiche Farbe pruefen.
+ while ( i>=0 && (color=field[i].color) ) {
+ // check left
+ if ( (i%sizex)!=0 && field[i-1].color==color)
+ goto check_gameover;
+ // check upward
+ if ( i>=sizex && field[i-sizex].color==color)
+ goto check_gameover;
+ i--;
+ }
+ }
+ check_gameover:
+ gameover=(i<0);
+ // kdDebug() << "<--gameover" << endl;
+ return (bool)gameover;
+}
+
+bool StoneField::gotBonus() const {
+ return m_gotBonus;
+}
+
+int
+StoneField::getBoard() const {
+ return board;
+}
+
+int
+StoneField::getScore() const {
+ return score;
+}
+
+int
+StoneField::getColors() const {
+ return colors;
+}
+
+int
+StoneField::getMarked() const {
+ return marked;
+}
+
+int
+StoneField::getFieldSize() const {
+ return maxstone;
+}
+
+struct Stone *
+StoneField::getField() const {
+ return field;
+}
+
+
+
+
+
+
+