Skip to content

Commit 9febf0b

Browse files
committed
Modify move-hint code to make use of the fact that solving lights out involves pressing each button N (mod states) times.
Fixes #8
1 parent 4a56049 commit 9febf0b

File tree

3 files changed

+72
-32
lines changed

3 files changed

+72
-32
lines changed

source/Light.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Light::Light(unsigned int states) {
4747

4848
this->states = states;
4949
state = 0;
50+
presses = 0;
5051

5152
paintMutex = SDL_CreateMutex();
5253

@@ -132,3 +133,19 @@ bool Light::paint(SDL_Surface& surface, unsigned int width, unsigned int height)
132133
}
133134
}
134135

136+
137+
void Light::press() {
138+
SDL_mutexP(paintMutex);
139+
presses++;
140+
if (presses >= states)
141+
presses = 0;
142+
143+
dirty = true;
144+
SDL_mutexV(paintMutex);
145+
}
146+
147+
148+
bool Light::shouldPress() const {
149+
return presses != 0;
150+
}
151+

source/Light.hpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ class Light : public Renderable {
6363
*/
6464
unsigned int state, states;
6565

66+
/**
67+
* The number of presses the light has recieved. A game of
68+
* LightsOut can be solved by pressing each light N (mod
69+
* states) times.
70+
*/
71+
unsigned int presses;
72+
6673
/**
6774
* A mutex to prevent the change of internal object state
6875
* while a paint is taking place (or vice-versa).
@@ -79,19 +86,37 @@ class Light : public Renderable {
7986
~Light();
8087

8188
/**
82-
* Returns true if the light is on.
89+
* Returns true if the light is on. This method is influenced
90+
* by calls to the "nextState" method.
8391
*/
8492
bool isLightOn() const;
8593

8694
/**
8795
* Cycles the light to the next available state. Lights at
8896
* the highest available state will be reset to the "off"
89-
* state.
97+
* state. The "press" method should be called in addition to
98+
* this if the light was the direct recipient of a press.
9099
*/
91100
void nextState();
92101

93102
bool paint(SDL_Surface& surface, unsigned int width, unsigned int height) const;
94103

104+
/**
105+
* Lets the light know that it was the direct recipeient of a
106+
* press. This is used to keep track of lights need to be
107+
* pressed to reset the game to an all-off state. The
108+
* "nextState" method should be called as well to ensure that
109+
* the light actually changes color from the press.
110+
*/
111+
void press();
112+
113+
/**
114+
* Returns true if the light should be pressed to arrive at
115+
* an all-off state. This method is influenced by calls to
116+
* the "press" method.
117+
*/
118+
bool shouldPress() const;
119+
95120
};
96121

97122

source/LightsOutGame.cpp

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -167,45 +167,42 @@ void LightsOutGame::eventOccured(const SDL_Event* const event) {
167167

168168

169169
void LightsOutGame::getMoveHint(unsigned int& suggestedX, unsigned int& suggestedY) const {
170+
bool won = winningState();
171+
if (won) {
172+
std::clog << SDL_GetTicks() << " (" << this << "): Game has already been won, providing bogus hint of (0,0)." << std::endl;
173+
suggestedX = 0;
174+
suggestedY = 0;
175+
return;
176+
}
177+
170178
SDL_mutexP(paintMutex);
171-
for (unsigned int y=0; y<lights->getHeight(); y++) {
172-
for (unsigned int x=0; x<lights->getWidth(); x++) {
173-
if (lights->getTile(x,y)->object->isLightOn()) {
174-
if (y+1 != lights->getHeight()) {
175-
//"Chase the lights"
176-
suggestedX = x;
177-
suggestedY = y+1;
178-
SDL_mutexV(paintMutex);
179-
return;
180-
}
181-
else {
182-
//Fixing the top
183-
suggestedY = 0;
184-
switch (x) {
185-
case 0: suggestedX = 1; SDL_mutexV(paintMutex); return;
186-
case 1: suggestedX = 0; SDL_mutexV(paintMutex); return;
187-
case 2: suggestedX = 3; SDL_mutexV(paintMutex); return;
188-
}
189-
}
190-
}
179+
bool moveAvailable = false;
180+
for (unsigned int x=0; x<lights->getWidth(); x++) {
181+
for (unsigned int y=0; y<lights->getHeight(); y++) {
182+
moveAvailable = moveAvailable || lights->getTile(x,y)->object->shouldPress();
191183
}
192184
}
193-
194-
//There's no reasonable "hint" for a board that has already won ;)
195-
if (winningState()) {
196-
std::clog << SDL_GetTicks() << " (" << this << "): Game has already been won, providing bogus hint of (0,0)." << std::endl;
185+
SDL_mutexV(paintMutex);
186+
if (!moveAvailable) {
187+
std::clog << SDL_GetTicks() << " (" << this << "): Game not won, yet no move available?? Providing bogus hint of (0,0)." << std::endl;
197188
suggestedX = 0;
198189
suggestedY = 0;
199-
SDL_mutexV(paintMutex);
200190
return;
201191
}
202192

203-
//Unsolvable
204-
//How on earth we got here after the constructor ensured
205-
//the board was solvable is beyond me.
206-
std::cerr << "Game is not solvable, cannot give move hint." << std::endl;
193+
SDL_mutexP(paintMutex);
194+
int x=0;
195+
int y=0;
196+
do {
197+
x = rand()%lights->getWidth();
198+
y = rand()%lights->getHeight();
199+
} while (!(lights->getTile(x,y)->object->shouldPress()));
207200
SDL_mutexV(paintMutex);
208-
throw 10;
201+
202+
suggestedX = x;
203+
suggestedY = y;
204+
205+
return;
209206
}
210207

211208

@@ -402,6 +399,7 @@ void LightsOutGame::pressButton(unsigned int x, unsigned int y) {
402399

403400
moves++;
404401

402+
lights->getTile(x,y)->object->press();
405403
toggleLight(x,y);
406404
toggleLight(x-1,y);
407405
toggleLight(x+1,y);

0 commit comments

Comments
 (0)