00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "StoneField.h"
00022 #include <assert.h>
00023
00024 StoneFieldState::StoneFieldState(const StoneField &stonefield)
00025 {
00026 field=new unsigned char[stonefield.maxstone];
00027 for (int i=0;i<stonefield.maxstone;i++)
00028 field[i]=stonefield.field[i].color;
00029
00030 colors=stonefield.colors;
00031 board=stonefield.board;
00032 score=stonefield.score;
00033 gameover=stonefield.gameover;
00034 }
00035
00036 StoneFieldState::~StoneFieldState() {
00037 delete[] field;
00038 }
00039
00040 void
00041 StoneFieldState::restore(StoneField &stonefield) const {
00042 for (int i=0;i<stonefield.maxstone;i++) {
00043 stonefield.field[i].color=field[i];
00044 stonefield.field[i].changed=true;
00045 stonefield.field[i].marked=false;
00046 }
00047
00048 stonefield.colors=colors;
00049 stonefield.board=board;
00050 stonefield.score=score;
00051 stonefield.marked=0;
00052 stonefield.gameover=gameover;
00053 }
00054
00055 StoneField::StoneField(int width, int height,
00056 int colors, unsigned int board,
00057 bool undoenabled)
00058 {
00059
00060
00061
00062 if (undoenabled) undolist=new QList<StoneFieldState>;
00063 else undolist=0;
00064
00065 sizex=width;
00066 sizey=height;
00067 maxstone=sizex*sizey;
00068 field=new Stone[maxstone];
00069 newGame(board,colors);
00070 m_gotBonus= false;
00071 }
00072
00073 StoneField::~StoneField() {
00074 delete[] field;
00075 delete undolist;
00076
00077 }
00078
00079 int
00080 StoneField::width() const {
00081 return sizex;
00082 }
00083
00084 int
00085 StoneField::height() const {
00086 return sizey;
00087 }
00088
00089 void
00090 StoneField::newGame(unsigned int board,int colors) {
00091
00092
00093 if (colors<1) colors=3;
00094 if (colors>7) colors=7;
00095 this->colors=colors;
00096 this->board=board;
00097 reset();
00098 }
00099
00100 void
00101 StoneField::reset() {
00102 random.setSeed(board);
00103
00104 Stone *stone=field;
00105 for (int i=0;i<maxstone;i++,stone++) {
00106 stone->color=1+random.getLong(colors);
00107 stone->marked=false;
00108 stone->changed=true;
00109 }
00110
00111 gameover=-1;
00112 score=0;
00113 marked=0;
00114
00115 if (undolist) {
00116 undolist->setAutoDelete(true);
00117 undolist->clear();
00118 }
00119
00120
00121 int c[7];
00122 int j;
00123 for (j=0;j<7;j++) c[j]=0;
00124
00125 for (j=0,stone=field;j<maxstone;j++,stone++) {
00126 c[stone->color]++;
00127 }
00128
00129
00130
00131
00132
00133 }
00134
00135 int
00136 StoneField::map(int x,int y) {
00137 assert (!(x<0||y<0||x>=sizex||y>=sizey));
00138 return x+y*sizex;
00139 }
00140
00141 int
00142 StoneField::mark(int x,int y,bool force) {
00143 int index=map(x,y);
00144
00145 if (index<0) {
00146 unmark();
00147 return 0;
00148 }
00149
00150 if (field[index].marked) return -1;
00151 unmark();
00152
00153 mark(index,field[index].color);
00154
00155 if (marked==1&&!force) {
00156 field[index].marked=false;
00157 marked=0;
00158 }
00159 return marked;
00160 }
00161
00162 void
00163 StoneField::mark(int index,unsigned char color) {
00164 if ( index<0 || index>=maxstone ) return;
00165
00166 Stone &stone=field[index];
00167
00168 if (stone.marked) return;
00169
00170 if (!stone.color || stone.color!=color) return;
00171
00172 stone.changed=true;
00173 stone.marked=true;
00174 marked++;
00175
00176
00177 if ((index%sizex)!=0) mark(index-1,color);
00178
00179 if (((index+1)%sizex)!=0) mark(index+1,color);
00180
00181 if (index>=sizex) mark(index-sizex,color);
00182
00183 if (index<(sizex-1)*sizey) mark(index+sizex,color);
00184 }
00185
00186 void
00187 StoneField::unmark() {
00188 if (!marked) return;
00189
00190 Stone *stone=field;
00191 for (int i=0;i<maxstone;i++,stone++) {
00192 stone->marked=false;
00193 stone->changed=true;
00194 }
00195 marked=0;
00196 }
00197
00198 int
00199 StoneField::remove(int x,int y,bool force) {
00200 int index=map(x,y);
00201
00202 if (index<0) return 0;
00203
00204 if (!field[index].marked) {
00205 mark(x,y,force);
00206 }
00207
00208 if (!marked) return 0;
00209
00210
00211 if (marked==1&&!force) return 0;
00212
00213
00214 if (undolist)
00215 undolist->append(new StoneFieldState(*this));
00216
00217
00218 if (marked>2)
00219 score+=(marked-2)*(marked-2);
00220
00221
00222 Stone *stone=field;
00223 for (int i=0;i<maxstone;i++,stone++) {
00224 if (stone->marked) {
00225 stone->color=0;
00226 stone->changed=true;
00227 stone->marked=false;
00228 }
00229 }
00230 int removed=marked;
00231 marked=0;
00232
00233 for (int col=0;col<sizex;col++) {
00234 int i1=col+maxstone-sizex;
00235 while ( i1>=0 && field[i1].color ) i1-=sizex;
00236 int i2=i1;
00237 while (i2>=0) {
00238 while ( i2>=0 && !field[i2].color ) i2-=sizex;
00239 while ( i2>=0 && field[i2].color ) {
00240 field[i1].color=field[i2].color;
00241 field[i1].changed=true;
00242 field[i2].color=0;
00243 field[i2].changed=true;
00244 i1-=sizex;
00245 i2-=sizex;
00246 }
00247 }
00248 }
00249
00250
00251 int lastcol = sizex;
00252 while (lastcol > 0 && !field[map(lastcol-1, sizey-1)].color) {
00253 lastcol--;
00254 }
00255
00256 for (int col=0;col<lastcol-1;) {
00257 bool empty = true;
00258 for (int row = 0; row < sizey; row++)
00259 if (field[map(col, row)].color) {
00260 empty = false;
00261 break;
00262 }
00263 if (!empty) {
00264 col++;
00265 continue;
00266 }
00267 int nextfullcol = col + 1;
00268 while (nextfullcol < sizex &&
00269 !field[map(nextfullcol, sizey - 1)].color)
00270 nextfullcol++;
00271
00272 if (nextfullcol > sizex - 1)
00273 break;
00274
00275 for (int row=0; row < sizey; row++) {
00276 int source = map(nextfullcol, row);
00277 int dest = map(col, row);
00278 field[dest].color=field[source].color;
00279 field[dest].changed=true;
00280 field[source].color=0;
00281 field[source].changed=true;
00282 }
00283 }
00284
00285
00286 if (!field[map(0, sizey-1)].color) {
00287 score+=1000;
00288 m_gotBonus= true;
00289 }
00290
00291
00292 gameover=-1;
00293 return removed;
00294 }
00295
00296 bool StoneField::undoPossible() const {
00297 return !(!undolist||undolist->isEmpty());
00298 }
00299
00300 int
00301 StoneField::undo(int count) {
00302 if (!undoPossible())
00303 return 0;
00304 if (count <= 0)
00305 return 0;
00306 int undocount=1;
00307 StoneFieldState *state=0;
00308 undolist->setAutoDelete(true);
00309 while (--count>0) {
00310 if (undolist->count()==1) break;
00311 undolist->removeLast();
00312 undocount++;
00313 }
00314 state=undolist->getLast();
00315
00316 state->restore(*this);
00317 undolist->removeLast();
00318 return undocount;
00319 }
00320
00321 bool
00322 StoneField::isGameover() const {
00323 register int i=maxstone-1;;
00324 register unsigned char color;
00325
00326 if (gameover>=0) return (bool)gameover;
00327
00328
00329 while (i>=0) {
00330
00331
00332 while ( i>=0 && field[i].color==0 ) i--;
00333
00334
00335 while ( i>=0 && (color=field[i].color) ) {
00336
00337 if ( (i%sizex)!=0 && field[i-1].color==color)
00338 goto check_gameover;
00339
00340 if ( i>=sizex && field[i-sizex].color==color)
00341 goto check_gameover;
00342 i--;
00343 }
00344 }
00345 check_gameover:
00346 gameover=(i<0);
00347
00348 return (bool)gameover;
00349 }
00350
00351 bool StoneField::gotBonus() const {
00352 return m_gotBonus;
00353 }
00354
00355 void StoneField::clearBonus() {
00356 m_gotBonus = false;
00357 }
00358
00359 int
00360 StoneField::getBoard() const {
00361 return board;
00362 }
00363
00364 int
00365 StoneField::getScore() const {
00366 return score;
00367 }
00368
00369 int
00370 StoneField::getColors() const {
00371 return colors;
00372 }
00373
00374 int
00375 StoneField::getMarked() const {
00376 return marked;
00377 }
00378
00379 int
00380 StoneField::getFieldSize() const {
00381 return maxstone;
00382 }
00383
00384 struct Stone *
00385 StoneField::getField() const {
00386 return field;
00387 }
00388
00389
00390
00391
00392
00393
00394