]> Shamusworld >> Repos - warehouse-man-deluxe/blob - src/gameboard.cpp
Added undo move system, various improvements.
[warehouse-man-deluxe] / src / gameboard.cpp
1 //
2 // gameboard.cpp: Game board class implementation
3 //
4 // by James Hammons
5 // © 2014 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // Who  When        What
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  03/01/2014  Created this file
12 //
13
14 #include "gameboard.h"
15 #include <string.h>
16 //#include <stdio.h>    // for printf()
17 #include "boards.h"
18
19
20 GameBoard::GameBoard(int boardNumber)
21 {
22         // Sanity check
23         if (boardNumber > NUMBER_OF_BOARDS)
24                 boardNumber = NUMBER_OF_BOARDS;
25
26         // boardNumber is 1-based
27         Board * boardToUse = (Board *)boards[boardNumber - 1];
28
29         width = boardToUse->width;
30         height = boardToUse->height;
31         boardLength = width * height;
32         board = new char[boardLength];
33         initialBoard = new char[boardLength];
34 //      initialX = boardToUse->x;
35 //      initialY = boardToUse->y;
36
37         for(int i=0; i<boardLength; i++)
38         {
39                 char c = boardToUse->state[i];
40
41                 if (c == '@')
42                         initialBoard[i] = GTWall;
43                 else if (c == ' ')
44                         initialBoard[i] = GTSpace;
45                 else if (c == 'X')
46                         initialBoard[i] = GTBox;
47                 else if (c == '.')
48                         initialBoard[i] = GTBoxSpot;
49                 else if (c == '+')
50                         initialBoard[i] = GTBox | GTBoxSpot;
51                 else if (c == 'o')
52                 {
53                         initialBoard[i] = GTSpace;
54                         initialX = i % width, initialY = i / width;
55                 }
56         }
57
58         ResetGame();
59 }
60
61
62 GameBoard::~GameBoard()
63 {
64         if (board)
65                 delete[] board;
66
67         if (initialBoard)
68                 delete[] initialBoard;
69 }
70
71
72 bool GameBoard::GameHasBeenWon(void)
73 {
74         // Check to see if all boxes are on their spots
75         for(int i=0; i<boardLength; i++)
76         {
77                 char cell = board[i] & ~GTBoxSpot;
78
79                 if ((cell == GTBox) && !(board[i] & GTBoxSpot))
80                         return false;
81         }
82
83         return true;
84 }
85
86
87 void GameBoard::ResetGame(void)
88 {
89         memcpy(board, initialBoard, boardLength);
90         playerX = initialX, playerY = initialY;
91         numMoves = 0;
92 }
93
94
95 int GameBoard::MovePlayerN(void)
96 {
97         // Sanity check (player trying to move into wall)
98         if (playerY == 1)
99                 return PMInvalid;
100
101         char cell1 = board[playerX + ((playerY - 1) * width)] & ~GTBoxSpot;
102         char cell2 = board[playerX + ((playerY - 2) * width)] & ~GTBoxSpot;
103
104         return Move(0, -1, cell1, cell2);
105 }
106
107
108 int GameBoard::MovePlayerS(void)
109 {
110         // Sanity check (player trying to move into wall)
111         if (playerY == (height - 2))
112                 return PMInvalid;
113
114         char cell1 = board[playerX + ((playerY + 1) * width)] & ~GTBoxSpot;
115         char cell2 = board[playerX + ((playerY + 2) * width)] & ~GTBoxSpot;
116
117         return Move(0, +1, cell1, cell2);
118 }
119
120
121 int GameBoard::MovePlayerE(void)
122 {
123         // Sanity check (player trying to move into wall)
124         if (playerX == (width - 2))
125                 return PMInvalid;
126
127         char cell1 = board[(playerX + 1) + (playerY * width)] & ~GTBoxSpot;
128         char cell2 = board[(playerX + 2) + (playerY * width)] & ~GTBoxSpot;
129
130         return Move(+1, 0, cell1, cell2);
131 }
132
133
134 int GameBoard::MovePlayerW(void)
135 {
136         // Sanity check (player trying to move into wall)
137         if (playerX == 1)
138                 return PMInvalid;
139
140         char cell1 = board[(playerX - 1) + (playerY * width)] & ~GTBoxSpot;
141         char cell2 = board[(playerX - 2) + (playerY * width)] & ~GTBoxSpot;
142
143         return Move(-1, 0, cell1, cell2);
144 }
145
146
147 int GameBoard::Move(int dx, int dy, char cell1, char cell2)
148 {
149         // Player is moving into an unoccupied space...
150         if (cell1 == GTSpace)
151         {
152 //              var += direction;
153                 playerX += dx, playerY += dy;
154                 undo[numMoves].dx = dx, undo[numMoves].dy = dy, undo[numMoves].type = PMWalk;
155                 numMoves++;
156                 return PMWalk;
157         }
158         // Player is pushing a box into an unoccupied space...
159         else if ((cell1 == GTBox) && (cell2 == GTSpace))
160         {
161 //              var += direction;
162                 playerX += dx, playerY += dy;
163                 board[playerX + (playerY * width)] &= GTBoxSpot;
164 //              var += direction;
165                 playerX += dx, playerY += dy;
166                 board[playerX + (playerY * width)] |= GTBox;
167 //              var -= direction;
168                 playerX -= dx, playerY -= dy;
169                 undo[numMoves].dx = dx, undo[numMoves].dy = dy, undo[numMoves].type = PMPush;
170                 numMoves++;
171                 return PMPush;
172         }
173
174         // All other combinations are no good
175         return PMInvalid;
176 }
177
178
179 bool GameBoard::IsBoxNOfPlayer(void)
180 {
181         if ((board[playerX + ((playerY - 1) * width)] & ~GTBoxSpot) == GTBox)
182                 return true;
183
184         return false;
185 }
186
187
188 bool GameBoard::IsBoxSOfPlayer(void)
189 {
190         if ((board[playerX + ((playerY + 1) * width)] & ~GTBoxSpot) == GTBox)
191                 return true;
192
193         return false;
194 }
195
196
197 bool GameBoard::IsBoxEOfPlayer(void)
198 {
199         if ((board[(playerX + 1) + (playerY * width)] & ~GTBoxSpot) == GTBox)
200                 return true;
201
202         return false;
203 }
204
205
206 bool GameBoard::IsBoxWOfPlayer(void)
207 {
208         if ((board[(playerX - 1) + (playerY * width)] & ~GTBoxSpot) == GTBox)
209                 return true;
210
211         return false;
212 }
213
214
215 bool GameBoard::UndoLastMove(int & dx, int & dy, int & type)
216 {
217         if (numMoves == 0)
218                 return false;
219
220         numMoves--;
221         dx = undo[numMoves].dx;
222         dy = undo[numMoves].dy;
223         type = undo[numMoves].type;
224
225         // Undo the box's move (if any)
226         if (type == PMPush)
227         {
228                 int boxPosition = (playerX + dx) + ((playerY + dy) * width);
229                 int newBoxPosition = playerX + (playerY * width);
230
231                 board[boxPosition] &= GTBoxSpot;
232 //              board[newBoxPosition] &= GTBoxSpot;     // This is extraneous
233                 board[newBoxPosition] |= GTBox;
234         }
235
236         // Undo the player's move
237         playerX += -dx;
238         playerY += -dy;
239
240         return true;
241 }
242