Added "Show Solution"
[vexed] / playfield.cpp
1 #include "playfield.h"
2 #include <stdio.h>
3 PlayField::PlayField(const QString &_title, const QString &_board, const QString &_solution):title(_title),solution(_solution)
4 {
5     for(int w=0;w<PF::FIELD_WIDTH;w++)
6         for(int h=0;h<PF::FIELD_HEIGHT;h++)
7             field[w][h]=PF::CELL_WALL;
8     QStringList rows=_board.split("/");
9     QListIterator<QString> rowI(rows);
10     int h=0;
11     while(rowI.hasNext())
12     {
13         QString row=rowI.next();
14         int w=0;
15         for(int i=0;i<row.size();i++)
16         {
17             char ch=row[i].toAscii();
18             int c=0;
19             while(ch>='0' && ch<='9')
20             {
21                 c=c*10+ch-'0';
22                 ch=row[++i].toAscii();
23                 if(i>=row.size()) break;
24             }
25             w+=c;
26             if(ch=='~')
27             {
28                 field[w++][h]=PF::CELL_EMPTY;
29             }
30             if(ch>='a' && ch <= 'h')
31             {
32                 field[w++][h]=ch-'a'+2;
33             }
34         }
35         h++;
36     }
37 }
38
39 void PlayField::move(int w, int h, int w_new)
40 {
41         if((w_new < 0) ||
42            (w_new >= PF::FIELD_WIDTH) || w == w_new)
43         {
44                 return;
45         }
46         if(get(w,h)==PF::CELL_EMPTY ||
47            get(w,h)==PF::CELL_WALL)
48         {
49                 return;
50         }
51         int d=w>w_new?-1:1;
52
53         Field temp;
54         int movesTemp=moves;
55         copy(field,temp);
56
57         bool moved=false;
58         bool cont;
59
60         int h_below=h+1;
61         do
62         {            
63             cont=moveBlock(w,h,d,0);
64             w+=d;
65             if(cont){
66                 moves++;
67                 moved=true;
68             }//if coordination has changed, inc the moves
69         } while(cont && (w!=w_new) && ((h_below >= PF::FIELD_HEIGHT) || get(w,h_below)!=PF::CELL_EMPTY));
70         do
71         {
72             cont=false;
73             cont|=checkGlobalFall();
74             cont|=checkTouch();
75         } while(cont);
76         if(moved)
77         {
78             if(totalUndo<PF::MAX_UNDO) totalUndo++;
79             copy(temp,undos[currentUndo]);
80             undoMade[currentUndo]=movesTemp;
81             currentUndo=(currentUndo + 1) % PF::MAX_UNDO;
82         }
83 }
84
85 bool PlayField::moveBlock(int w, int h, int dw, int dh)
86 {
87     int wn=w+dw;
88     int hn=h+dh;
89
90     if(wn<0 || wn >= PF::FIELD_WIDTH || hn < 0 || hn >= PF::FIELD_HEIGHT)
91         return false;
92
93     if(get(wn,hn)!=PF::CELL_EMPTY)
94         return false;
95     set(wn, hn, get(w,h));
96     set(w,h,PF::CELL_EMPTY);
97     emit cellMoved(w,h,wn,hn);
98     return true;
99 }
100 bool PlayField::checkGlobalFall()
101 {
102     bool fall;
103     bool fallen=false;
104     do
105     {
106         fall=false;
107         for(int w=0;w<PF::FIELD_WIDTH;w++)
108             for(int h=0;h<PF::FIELD_HEIGHT;h++)
109                 if(checkFall(w,h))
110                 {
111                     if(moveBlock(w,h,0,1))
112                     {
113                         fall=true;
114                         fallen=true;
115                     }
116                 }
117     } while(fall);
118     return fallen;
119 }
120
121 bool PlayField::checkFall(int w, int h)
122 {
123     int cell=get(w,h);
124     return (cell!=PF::CELL_EMPTY) &&
125             (cell!=PF::CELL_WALL) &&
126             (h!=(PF::FIELD_HEIGHT-1)) &&
127             (get(w,h+1)==PF::CELL_EMPTY);
128 }
129 bool PlayField::checkTouch()
130 {
131     int toHide[PF::FIELD_WIDTH][PF::FIELD_HEIGHT];
132
133     for (int w = 0; w < PF::FIELD_WIDTH; w++) {
134             for (int h = 0; h < PF::FIELD_HEIGHT; h++) {
135                     toHide[w][h] = PF::CELL_EMPTY;
136                     if ((get(w,h) != PF::CELL_EMPTY) && (get(w,h)!=PF::CELL_WALL)) {
137                             if (h != 0) {
138                                     toHide[w][h] |= (get(w,h-1) == get(w,h));
139                             }
140                             if (h != PF::FIELD_HEIGHT - 1) {
141                                     toHide[w][h] |= (get(w,h+1) == get(w,h));
142                             }
143                             if (w != 0) {
144                                     toHide[w][h] |= (get(w-1,h) == get(w,h));
145                             }
146                             if (w != PF::FIELD_WIDTH - 1) {
147                                     toHide[w][h] |= (get(w+1,h) == get(w,h));
148                             }
149                     }
150             }
151     }
152
153     bool touched=false;
154     for (int w = 0; w < PF::FIELD_WIDTH; w++) {
155             for (int h = 0; h < PF::FIELD_HEIGHT; h++) {
156                     if(toHide[w][h])
157                     {
158                             set(w,h,PF::CELL_EMPTY);
159                             emit cellGone(w,h);
160                             touched=true;
161                     }
162             }
163     }
164     return touched;
165 }
166
167 bool PlayField::checkSolved()
168 {
169         for(int w=0;w<PF::FIELD_WIDTH-1;w++)
170                 for(int h=0;h<PF::FIELD_HEIGHT-1;h++)
171                 {
172                         int cell=get(w,h);
173                         if((cell!=PF::CELL_EMPTY) && (cell!=PF::CELL_WALL)) return false;
174                 }
175         return true;
176 }
177
178 void PlayField::undo()
179 {
180     if(totalUndo > 0)
181     {
182         totalUndo--;
183         currentUndo=(currentUndo - 1 + PF::MAX_UNDO) % PF::MAX_UNDO;
184         copy(undos[currentUndo],field);
185         moves=undoMade[currentUndo];
186     }
187 }