diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | c90c389a8a8d9d8661e9772ec4144c5cf2039f23 (patch) | |
tree | 6d8391395bce9eaea4ad78958617edb20c6a7573 /ksame/StoneField.cpp | |
download | tdegames-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.cpp | 399 |
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; +} + + + + + + + |