]> git.saurik.com Git - wxWidgets.git/blob - demos/bombs/bombs1.cpp
As per the docs, the value returned is -1 if the value entered is out of range [patch...
[wxWidgets.git] / demos / bombs / bombs1.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: bombs1.cpp
3 // Purpose: Bombs game
4 // Author: P. Foggia 1996
5 // Modified by: Wlodzimierz Skiba (ABX) 2003
6 // Created: 1996
7 // RCS-ID: $Id$
8 // Copyright: (c) 1996 P. Foggia
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 /*
13 * implementation of the methods DrawField and OnEvent of the
14 * class BombsCanvas
15 */
16
17 #ifdef __GNUG__
18 # pragma implementation
19 #endif
20
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 # pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 # include "wx/wx.h"
29 #endif //precompiled headers
30
31 #include "bombs.h"
32
33 // Draws the field on the device context dc
34 // xc1,yc1 etc. are the (inclusive) limits of the area to be drawn,
35 // expressed in cells.
36 void BombsCanvas::DrawField(wxDC *dc, int xc1, int yc1, int xc2, int yc2)
37 {
38 wxString buf;
39 long chw, chh;
40
41 wxColour wxBlack = wxTheColourDatabase->Find(wxT("BLACK"));
42 wxColour wxWhite = wxTheColourDatabase->Find(wxT("WHITE"));
43 wxColour wxRed = wxTheColourDatabase->Find(wxT("RED"));
44 wxColour wxBlue = wxTheColourDatabase->Find(wxT("BLUE"));
45 wxColour wxGrey = wxTheColourDatabase->Find(wxT("LIGHT GREY"));
46 wxColour wxFocused = wxTheColourDatabase->Find(wxT("GREY"));
47 wxColour wxGreen = wxTheColourDatabase->Find(wxT("GREEN"));
48
49 wxPen *blackPen = wxThePenList->FindOrCreatePen(wxBlack, 1, wxSOLID);
50 wxPen *redPen = wxThePenList->FindOrCreatePen(wxRed, 1, wxSOLID);
51 wxPen *bluePen = wxThePenList->FindOrCreatePen(wxBlue, 1, wxSOLID);
52 wxBrush *whiteBrush = wxTheBrushList->FindOrCreateBrush(wxWhite, wxSOLID);
53 wxBrush *greyBrush = wxTheBrushList->FindOrCreateBrush(wxGrey, wxSOLID);
54 wxBrush *focusedBrush = wxTheBrushList->FindOrCreateBrush(wxFocused, wxSOLID);
55 wxBrush *redBrush = wxTheBrushList->FindOrCreateBrush(wxRed, wxSOLID);
56
57 dc->SetPen(* blackPen);
58
59 int x, y;
60 int xMax = this->GetGridSizeInPixels().GetWidth();
61 int yMax = this->GetGridSizeInPixels().GetHeight();
62 for(x=xc1; x<=xc2; x++)
63 dc->DrawLine(x*m_cellWidth*X_UNIT, 0, x*m_cellWidth*X_UNIT, yMax);
64 for(y=xc1; y<=yc2; y++)
65 dc->DrawLine(0, y*m_cellHeight*Y_UNIT, xMax, y*m_cellHeight*Y_UNIT);
66
67
68 wxFont font= BOMBS_FONT;
69 dc->SetFont(font);
70
71 for(x=xc1; x<=xc2; x++)
72 for(y=yc1; y<=yc2; y++)
73 {
74 if (m_game->IsMarked(x,y))
75 {
76 dc->SetPen(* blackPen);
77
78 if (m_game->IsFocussed(x, y))
79 dc->SetBrush(* focusedBrush);
80 else
81 dc->SetBrush(* greyBrush);
82
83 dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
84 m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
85 buf = wxT("M");
86 if (!m_game->IsHidden(x,y) && m_game->IsBomb(x,y))
87 dc->SetTextForeground(wxBlue);
88 else
89 dc->SetTextForeground(wxRed);
90
91 dc->SetTextBackground(wxGrey);
92 dc->GetTextExtent(buf, &chw, &chh);
93 dc->DrawText( buf,
94 x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
95 y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2 );
96
97 if (!m_game->IsHidden(x,y) && m_game->IsBomb(x,y))
98 {
99 dc->SetPen(*redPen);
100 dc->DrawLine(x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
101 (x+1)*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT);
102 dc->DrawLine(x*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT,
103 (x+1)*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT);
104 }
105 }
106 else if (m_game->IsHidden(x,y))
107 {
108 dc->SetPen(*blackPen);
109 if (m_game->IsFocussed(x, y))
110 dc->SetBrush(* focusedBrush);
111 else
112 dc->SetBrush(*greyBrush);
113
114 dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
115 m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
116 }
117 else if (m_game->IsBomb(x,y))
118 {
119 dc->SetPen(* blackPen);
120 dc->SetBrush(* redBrush);
121 dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
122 m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
123 buf = wxT("B");
124 dc->SetTextForeground(wxBlack);
125 dc->SetTextBackground(wxRed);
126 dc->GetTextExtent(buf, &chw, &chh);
127 dc->DrawText( buf,
128 x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
129 y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2);
130 if (m_game->IsExploded(x,y))
131 {
132 dc->SetPen(* bluePen);
133 dc->DrawLine(x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
134 (x+1)*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT);
135 dc->DrawLine(x*m_cellWidth*X_UNIT, (y+1)*m_cellHeight*Y_UNIT,
136 (x+1)*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT);
137 }
138 }
139 else // Display a digit
140 {
141 dc->SetPen(* blackPen);
142 if (m_game->IsFocussed(x, y))
143 dc->SetBrush(* focusedBrush);
144 else
145 dc->SetBrush(* whiteBrush);
146 dc->DrawRectangle( x*m_cellWidth*X_UNIT, y*m_cellHeight*Y_UNIT,
147 m_cellWidth*X_UNIT+1, m_cellHeight*Y_UNIT+1);
148
149 int digit_value = m_game->Get(x,y) & BG_MASK;
150 switch(digit_value)
151 {
152 case 0:
153 buf = wxT("0");
154 dc->SetTextForeground(wxGreen);
155 break;
156 case 1:
157 buf = wxT("1");
158 dc->SetTextForeground(wxBlue);
159 break;
160 default:
161 buf.Printf(wxT("%d"),digit_value);
162 dc->SetTextForeground(wxBlack);
163 break;
164 }
165 dc->GetTextExtent(buf, &chw, &chh);
166 dc->SetTextBackground(wxWhite);
167 dc->DrawText( buf,
168 x*m_cellWidth*X_UNIT + (m_cellWidth*X_UNIT-chw)/2,
169 y*m_cellHeight*Y_UNIT + (m_cellHeight*Y_UNIT-chh)/2);
170 }
171 }
172 dc->SetFont(wxNullFont);
173
174 wxString msg;
175 msg.Printf(wxT("%d bombs %d remaining cells"),
176 m_game->GetNumBombs(), m_game->GetNumRemainingCells() );
177
178 #if wxUSE_LOG && wxUSE_STATUSBAR
179 wxLogStatus(msg);
180 #else
181 this->GetParent()->SetTitle(msg);
182 #endif
183 }
184
185 // Refreshes the field image
186 // xc1,yc1 etc. are the (inclusive) limits of the area to be drawn,
187 // expressed in cells.
188 void BombsCanvas::RefreshField(int xc1, int yc1, int xc2, int yc2)
189 {
190 wxClientDC dc(this);
191 DrawField(& dc, xc1, yc1, xc2, yc2);
192 if (m_bmp)
193 {
194 wxMemoryDC memDC;
195 memDC.SelectObject(*m_bmp);
196 DrawField(&memDC, xc1, yc1, xc2, yc2);
197 memDC.SelectObject(wxNullBitmap);
198 }
199 }
200
201 // Called when uncovering a cell.
202 void BombsCanvas::Uncover(int x, int y)
203 {
204 m_game->Unhide(x,y);
205 RefreshField(x, y, x, y);
206
207 const int gridWidth = m_game->GetWidth();
208 const int gridHeight = m_game->GetHeight();
209
210 const bool hasWon = m_game->GetNumRemainingCells() == 0;
211 if (m_game->IsBomb(x,y) || hasWon)
212 {
213 wxBell();
214 if (hasWon)
215 {
216 wxMessageBox(wxT("Nice! You found all the bombs!"),
217 wxT("wxWin Bombs"), wxOK|wxCENTRE);
218 }
219 else // x,y is a bomb
220 {
221 m_game->Explode(x, y);
222 }
223
224 for(x=0; x<gridWidth; x++)
225 for(y=0; y<gridHeight; y++)
226 m_game->Unhide(x,y);
227 RefreshField(0, 0, gridWidth-1, gridHeight-1);
228 }
229 else if (!m_game->Get(x, y))
230 {
231 int left = ( x > 0 ) ? x-1 : 0;
232 int right = ( x < gridWidth - 1 )
233 ? x+1
234 : gridWidth - 1;
235 int top = ( y > 0 ) ? y-1 : 0;
236 int bottom = ( y < gridHeight - 1 )
237 ? y+1
238 : gridHeight - 1;
239
240 int i, j;
241 for (j=top; j<=bottom; j++)
242 for (i=left; i<=right; i++)
243 if ( (i != x || j != y) && m_game->IsHidden(i, j)
244 && !m_game->IsMarked(i, j) )
245 {
246 Uncover(i, j);
247 }
248 }
249 }
250
251 // Called when the canvas receives a mouse event.
252 void BombsCanvas::OnMouseEvent(wxMouseEvent& event)
253 {
254 const int gridWidth = m_game->GetWidth();
255 const int gridHeight = m_game->GetHeight();
256
257 wxCoord fx, fy;
258 event.GetPosition(&fx, &fy);
259 int x = fx/(m_cellWidth*X_UNIT);
260 int y = fy/(m_cellHeight*Y_UNIT);
261 if (x<gridWidth && y<gridHeight)
262 {
263 if ( (event.RightDown() || (event.LeftDown() && event.ShiftDown()))
264 && (m_game->IsHidden(x,y)
265 || !m_game->GetNumRemainingCells() ) )
266 {
267 // store previous and current field
268 int prevFocusX = m_game->m_gridFocusX;
269 int prevFocusY = m_game->m_gridFocusY;
270 m_game->m_gridFocusX = x;
271 m_game->m_gridFocusY = y;
272 RefreshField(prevFocusX, prevFocusY, prevFocusX, prevFocusY);
273 m_game->Mark(x, y);
274 RefreshField(x, y, x, y);
275 return;
276 }
277 else if (event.LeftDown() && m_game->IsHidden(x,y)
278 && !m_game->IsMarked(x,y))
279 {
280 // store previous and current field
281 int prevGridFocusX = m_game->m_gridFocusX;
282 int prevGridFocusY = m_game->m_gridFocusY;
283 m_game->m_gridFocusX = x;
284 m_game->m_gridFocusY = y;
285 RefreshField(prevGridFocusX, prevGridFocusY,
286 prevGridFocusX, prevGridFocusY);
287 Uncover(x, y);
288 return;
289 }
290 }
291 }
292
293 void BombsCanvas::OnChar(wxKeyEvent& event)
294 {
295 int keyCode = event.GetKeyCode();
296 int prevGridFocusX = m_game->m_gridFocusX;
297 int prevGridFocusY = m_game->m_gridFocusY;
298
299 const int gridWidth = m_game->GetWidth();
300 const int gridHeight = m_game->GetHeight();
301
302 switch(keyCode)
303 {
304
305 case WXK_RIGHT:
306 m_game->m_gridFocusX++;
307 if (m_game->m_gridFocusX >= gridWidth) m_game->m_gridFocusX = 0;
308 break;
309
310 case WXK_LEFT:
311 m_game->m_gridFocusX--;
312 if (m_game->m_gridFocusX<0) m_game->m_gridFocusX = gridWidth-1;
313 break;
314
315 case WXK_DOWN:
316 m_game->m_gridFocusY++;
317 if (m_game->m_gridFocusY >= gridHeight) m_game->m_gridFocusY = 0;
318 break;
319
320 case WXK_UP:
321 m_game->m_gridFocusY--;
322 if (m_game->m_gridFocusY<0) m_game->m_gridFocusY = gridHeight-1;
323 break;
324
325 case WXK_RETURN:
326 if ( (prevGridFocusX == m_game->m_gridFocusX)
327 && (prevGridFocusY == m_game->m_gridFocusY)
328 && (m_game->IsHidden(m_game->m_gridFocusX, m_game->m_gridFocusY)) )
329 {
330 m_game->Mark(m_game->m_gridFocusX, m_game->m_gridFocusY);
331 if (!m_game->IsMarked(m_game->m_gridFocusX, m_game->m_gridFocusY))
332 {
333 Uncover(m_game->m_gridFocusX, m_game->m_gridFocusY);
334 }
335 RefreshField(m_game->m_gridFocusX, m_game->m_gridFocusY,
336 m_game->m_gridFocusX, m_game->m_gridFocusY);
337 }
338 break;
339
340 default:
341 event.Skip();
342
343 }
344
345 if ((prevGridFocusX != m_game->m_gridFocusX)
346 || (prevGridFocusY != m_game->m_gridFocusY))
347 {
348 // cause focused field to be visible after first key hit after launching new game
349 if( m_game->m_gridFocusX < 0 ) m_game->m_gridFocusX = 0;
350 if( m_game->m_gridFocusY < 0 ) m_game->m_gridFocusY = 0;
351
352 // refresh previous field and focused field
353 RefreshField(prevGridFocusX, prevGridFocusY,
354 prevGridFocusX, prevGridFocusY);
355 RefreshField(m_game->m_gridFocusX, m_game->m_gridFocusY,
356 m_game->m_gridFocusX, m_game->m_gridFocusY);
357 }
358 }