about summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--freecell.c64
1 files changed, 40 insertions, 24 deletions
diff --git a/freecell.c b/freecell.c
index 39bdb12..bc38bf8 100644
--- a/freecell.c
+++ b/freecell.c
@@ -25,8 +25,6 @@
 #include "layout.h"
 #include "stack.h"
 
-#define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))
-
 enum {
 	Foundation1,
 	Foundation2,
@@ -51,6 +49,12 @@ static struct Stack stacks[StacksLen];
 
 static uint kingFace = Cards_KingRight;
 
+static struct {
+	bool avail;
+	uint dst;
+	uint src;
+} undo;
+
 static void gameDeal(void) {
 	for (uint i = 0; i < StacksLen; ++i) {
 		stackClear(&stacks[i]);
@@ -67,6 +71,7 @@ static void gameDeal(void) {
 		stackMoveTo(&stacks[i], &deck, 6);
 	}
 	kingFace = Cards_KingRight;
+	undo.avail = false;
 }
 
 static bool gameWin(void) {
@@ -92,28 +97,38 @@ static bool gameAvail(Card card) {
 	return card == stackTop(&stacks[stack]);
 }
 
-static bool gameMove(uint dest, Card card) {
-	uint source, index;
-	if (!gameFind(&source, &index, card)) return false;
-	Card destTop = stackTop(&stacks[dest]);
+static bool gameMove(uint dst, Card card) {
+	uint src, index;
+	if (!gameFind(&src, &index, card)) return false;
+	Card top = stackTop(&stacks[dst]);
 
-	if (source == dest) return false;
-	if (dest >= Cell1 && dest <= Cell4) {
-		if (stacks[dest].len) return false;
+	if (src == dst) return false;
+	if (dst >= Cell1 && dst <= Cell4) {
+		if (stacks[dst].len) return false;
 		kingFace = Cards_KingLeft;
 	}
-	if (dest >= Foundation1 && dest <= Foundation4) {
-		if (!destTop && cardRank(card) != Cards_A) return false;
-		if (destTop && cardSuit(card) != cardSuit(destTop)) return false;
-		if (destTop && cardRank(card) != cardRank(destTop) + 1) return false;
+	if (dst >= Foundation1 && dst <= Foundation4) {
+		if (!top && cardRank(card) != Cards_A) return false;
+		if (top && cardSuit(card) != cardSuit(top)) return false;
+		if (top && cardRank(card) != cardRank(top) + 1) return false;
 		kingFace = Cards_KingRight;
 	}
-	if (dest >= Tableau1 && dest <= Tableau8) {
-		if (destTop && cardColor(card) == cardColor(destTop)) return false;
-		if (destTop && cardRank(card) != cardRank(destTop) - 1) return false;
+	if (top >= Tableau1 && top <= Tableau8) {
+		if (top && cardColor(card) == cardColor(top)) return false;
+		if (top && cardRank(card) != cardRank(top) - 1) return false;
 	}
 
-	stackPush(&stacks[dest], stackPop(&stacks[source]));
+	undo.dst = src;
+	undo.src = dst;
+	undo.avail = true;
+	stackPush(&stacks[dst], stackPop(&stacks[src]));
+	return true;
+}
+
+static bool gameUndo(void) {
+	if (!undo.avail) return false;
+	stackPush(&stacks[undo.dst], stackPop(&stacks[undo.src]));
+	undo.avail = false;
 	return true;
 }
 
@@ -133,8 +148,8 @@ static bool gameAuto(void) {
 		if (cardRank(card) > Cards_2) {
 			if (min[!cardColor(card)] < cardRank(card)) continue;
 		}
-		for (uint dest = Foundation1; dest <= Foundation4; ++dest) {
-			if (gameMove(dest, card)) return true;
+		for (uint dst = Foundation1; dst <= Foundation4; ++dst) {
+			if (gameMove(dst, card)) return true;
 		}
 	}
 	return false;
@@ -220,6 +235,7 @@ static void revealRank(Card rank) {
 static bool keyDown(SDL_KeyboardEvent key) {
 	switch (key.keysym.sym) {
 		case SDLK_F2: gameDeal(); return true;
+		case SDLK_BACKSPACE: return gameUndo();
 	}
 	if (key.repeat) return false;
 	switch (key.keysym.sym) {
@@ -265,17 +281,17 @@ static bool mouseButtonDown(SDL_MouseButtonEvent button) {
 			if (!item) return false;
 			card = item->card;
 		}
-		for (uint dest = Cell1; dest <= Cell4; ++dest) {
-			if (gameMove(dest, card)) break;
+		for (uint dst = Cell1; dst <= Cell4; ++dst) {
+			if (gameMove(dst, card)) break;
 		}
 		layout.dragItem.card = 0;
 		return true;
 	}
 
 	if (layout.dragItem.card) {
-		for (uint dest = 0; dest < StacksLen; ++dest) {
-			if (SDL_PointInRect(&point, &stackRects[dest])) {
-				if (gameMove(dest, layout.dragItem.card)) break;
+		for (uint dst = 0; dst < StacksLen; ++dst) {
+			if (SDL_PointInRect(&point, &stackRects[dst])) {
+				if (gameMove(dst, layout.dragItem.card)) break;
 			}
 		}
 		layout.dragItem.card = 0;