summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--layout.h113
-rw-r--r--sol.c170
3 files changed, 154 insertions, 131 deletions
diff --git a/Makefile b/Makefile
index 8775fce..c843fc8 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ sol: cards.o sol.o
 
 $(OBJS): cards.h
 
-sol.o: stack.h
+sol.o: layout.h stack.h
 
 clean:
 	rm -f $(BINS) $(OBJS)
diff --git a/layout.h b/layout.h
new file mode 100644
index 0000000..1f55967
--- /dev/null
+++ b/layout.h
@@ -0,0 +1,113 @@
+/* Copyright (C) 2019  C. McEnroe <june@causal.agency>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LAYOUT_H
+#define LAYOUT_H
+
+#include <SDL_rect.h>
+#include <assert.h>
+
+#include "stack.h"
+
+#ifndef LAYOUT_CAP
+#define LAYOUT_CAP 64
+#endif
+
+typedef unsigned uint;
+
+struct Item {
+	SDL_Rect rect;
+	Card card;
+};
+
+struct List {
+	uint len;
+	struct Item items[LAYOUT_CAP];
+};
+
+static inline void
+listPush(struct List *list, const struct SDL_Rect *rect, Card card) {
+	assert(list->len < LAYOUT_CAP);
+	struct Item item = { *rect, card };
+	list->items[list->len++] = item;
+}
+
+static inline struct Item *listFind(struct List *list, const SDL_Point *point) {
+	for (uint i = list->len - 1; i < list->len; --i) {
+		if (SDL_PointInRect(point, &list->items[i].rect)) {
+			return &list->items[i];
+		}
+	}
+	return NULL;
+}
+
+struct Layout {
+	struct List main;
+	struct List drag;
+	struct Item dragItem;
+};
+
+static inline void layoutClear(struct Layout *layout) {
+	layout->main.len = 0;
+	layout->drag.len = 0;
+}
+
+struct Style {
+	uint increment;
+	int deltaXBack;
+	int deltaYBack;
+	int deltaXFront;
+	int deltaYFront;
+};
+
+static inline void
+layoutStack(
+	struct Layout *layout, SDL_Rect *rect,
+	const struct Stack *stack, const struct Style *style
+) {
+	struct List *list = &layout->main;
+	for (uint i = 0; i < stack->len; ++i) {
+		Card card = stack->cards[i];
+		if (card == layout->dragItem.card) {
+			list = &layout->drag;
+			*rect = layout->dragItem.rect;
+		}
+		listPush(list, rect, card);
+		if ((i + 1) % style->increment == 0) {
+			rect->x += (card > 0 ? style->deltaXFront : style->deltaXBack);
+			rect->y += (card > 0 ? style->deltaYFront : style->deltaYBack);
+		}
+	}
+}
+
+enum {
+	SquareIncrement = 24 / 3,
+	SquareDeltaX = 2,
+	SquareDeltaY = 1,
+
+	FanDownDeltaX = 0,
+	FanDownDeltaYBack = 3,
+	FanDownDeltaYFront = 15,
+};
+
+static const struct Style Square = {
+	SquareIncrement, SquareDeltaX, SquareDeltaY, SquareDeltaX, SquareDeltaY,
+};
+static const struct Style FanDown = {
+	1, FanDownDeltaX, FanDownDeltaYBack, FanDownDeltaX, FanDownDeltaYFront,
+};
+
+#endif
diff --git a/sol.c b/sol.c
index 16a688f..f91310a 100644
--- a/sol.c
+++ b/sol.c
@@ -22,12 +22,11 @@
 #include <time.h>
 
 #include "cards.h"
+#include "layout.h"
 #include "stack.h"
 
 #define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))
 
-typedef unsigned uint;
-
 enum {
 	Stock,
 	Waste1,
@@ -189,129 +188,47 @@ enum {
 	TableauX = StackMarginX,
 	TableauY = StockY + Cards_Height + StackMarginY,
 
-	StackDeltaX = 2,
-	StackDeltaY = 1,
-
-	Waste3DeltaX = 14,
-	Waste3DeltaY = StackDeltaY,
-
-	TableauDeltaX = 0,
-	TableauDeltaYBack = 3,
-	TableauDeltaYFront = 15,
-
 	WindowWidth = 7 * Cards_Width + 8 * StackMarginX,
 	WindowHeight = 2 * (StackMarginY + Cards_Height)
-		+ 6 * TableauDeltaYBack
-		+ 12 * TableauDeltaYFront
+		+ 6 * FanDownDeltaYBack
+		+ 12 * FanDownDeltaYFront
 		+ StackMarginY,
 };
 
-struct Item {
-	SDL_Rect rect;
-	uint texture;
-	Card card;
-};
-
-struct List {
-	uint len;
-	struct Item items[52];
-};
-
-static void listPush(struct List *list, struct Item item) {
-	assert(list->len < 52);
-	list->items[list->len++] = item;
-}
-
-static struct {
-	SDL_Rect stacks[StacksLen];
-	struct List base;
-	struct List main;
-	struct List drag;
-	struct Item dragItem;
-	uint backTexture;
-} layout;
-
-static struct Item *layoutFind(const SDL_Point *point) {
-	for (uint i = layout.main.len - 1; i < layout.main.len; --i) {
-		if (SDL_PointInRect(point, &layout.main.items[i].rect)) {
-			return &layout.main.items[i];
-		}
-	}
-	return NULL;
-}
-
-static void layoutClear(void) {
-	layout.base.len = 0;
-	layout.main.len = 0;
-	layout.drag.len = 0;
-}
+static const struct Style FanWaste3 = { 1, 14, SquareDeltaY, 14, SquareDeltaY };
 
-static void layoutCard(struct List **list, SDL_Rect *rect, Card card) {
-	if (card == layout.dragItem.card) {
-		*list = &layout.drag;
-		*rect = layout.dragItem.rect;
-	}
-	uint texture = (card > 0 ? (uint)card : layout.backTexture);
-	struct Item item = { *rect, texture, card };
-	listPush(*list, item);
-}
+static struct SDL_Rect stackRects[StacksLen];
+static struct Layout layout;
+static uint backTexture = Cards_Back1;
 
-static void layoutStack(SDL_Rect *rect, const struct Stack *stack, uint depth) {
-	struct List *list = &layout.main;
-	for (uint i = 0; i < stack->len; ++i) {
-		layoutCard(&list, rect, stack->cards[i]);
-		if (i > 0 && i % (depth / 3) == 0) {
-			rect->x += StackDeltaX;
-			rect->y += StackDeltaY;
-		}
-	}
-}
+static void updateLayout(void) {
+	layoutClear(&layout);
 
-static void layoutStock(void) {
-	SDL_Rect rect = { StockX, StockY, Cards_Width, Cards_Height };
-	struct Item item = { rect, Cards_O, 0 };
-	listPush(&layout.base, item);
-	layout.stacks[Stock] = rect;
-	layoutStack(&rect, &stacks[Stock], 24);
-}
+	SDL_Rect stock = { StockX, StockY, Cards_Width, Cards_Height };
+	stackRects[Stock] = stock;
+	listPush(&layout.main, &stock, Cards_O);
+	layoutStack(&layout, &stock, &stacks[Stock], &Square);
 
-static void layoutWaste(void) {
-	SDL_Rect rect = { WasteX, WasteY, Cards_Width, Cards_Height };
-	layoutStack(&rect, &stacks[Waste1], 24);
-	struct List *list = &layout.main;
-	for (uint i = 0; i < stacks[Waste3].len; ++i) {
-		layoutCard(&list, &rect, stacks[Waste3].cards[i]);
-		rect.x += Waste3DeltaX;
-		rect.y += Waste3DeltaY;
-	}
-}
+	SDL_Rect waste = { WasteX, WasteY, Cards_Width, Cards_Height };
+	layoutStack(&layout, &waste, &stacks[Waste1], &Square);
+	layoutStack(&layout, &waste, &stacks[Waste3], &FanWaste3);
 
-static void layoutFoundations(void) {
-	SDL_Rect base = { FoundationX, FoundationY, Cards_Width, Cards_Height };
+	SDL_Rect found = { FoundationX, FoundationY, Cards_Width, Cards_Height };
 	for (uint i = Foundation1; i <= Foundation4; ++i) {
-		struct Item item = { base, Cards_Empty, 0 };
-		listPush(&layout.base, item);
-		layout.stacks[i] = base;
-		SDL_Rect rect = base;
-		layoutStack(&rect, &stacks[i], 13);
-		base.x += Cards_Width + StackMarginX;
+		stackRects[i] = found;
+		listPush(&layout.main, &found, Cards_Empty);
+		SDL_Rect rect = found;
+		layoutStack(&layout, &rect, &stacks[i], &Square);
+		found.x += Cards_Width + StackMarginX;
 	}
-}
 
-static void layoutTableau(void) {
-	SDL_Rect base = { TableauX, TableauY, Cards_Width, Cards_Height };
+	SDL_Rect table = { TableauX, TableauY, Cards_Width, Cards_Height };
 	for (uint i = Tableau1; i <= Tableau7; ++i) {
-		SDL_Rect stack = { base.x, base.y, base.w, WindowHeight };
-		layout.stacks[i] = stack;
-		struct List *list = &layout.main;
-		SDL_Rect rect = base;
-		for (uint j = 0; j < stacks[i].len; ++j) {
-			Card card = stacks[i].cards[j];
-			layoutCard(&list, &rect, card);
-			rect.x += TableauDeltaX;
-			rect.y += (card > 0 ? TableauDeltaYFront : TableauDeltaYBack);
-		}
-		base.x += Cards_Width + StackMarginX;
+		stackRects[i] = table;
+		stackRects[i].h = WindowHeight;
+		SDL_Rect rect = table;
+		layoutStack(&layout, &rect, &stacks[i], &FanDown);
+		table.x += Cards_Width + StackMarginX;
 	}
 }
 
@@ -320,10 +237,10 @@ static bool keyDown(SDL_KeyboardEvent key) {
 		case SDLK_F2: gameDeal(); return true;
 		case SDLK_BACKSPACE: return gameUndo();
 		case SDLK_b: {
-			layout.backTexture -= Cards_Back1;
-			layout.backTexture += 1;
-			layout.backTexture %= 12;
-			layout.backTexture += Cards_Back1;
+			backTexture -= Cards_Back1;
+			backTexture += 1;
+			backTexture %= 12;
+			backTexture += Cards_Back1;
 			return true;
 		}
 		case SDLK_d: {
@@ -337,11 +254,11 @@ static bool keyDown(SDL_KeyboardEvent key) {
 
 static bool mouseButtonDown(SDL_MouseButtonEvent button) {
 	struct SDL_Point point = { button.x, button.y };
-	if (SDL_PointInRect(&point, &layout.stacks[Stock])) {
+	if (SDL_PointInRect(&point, &stackRects[Stock])) {
 		gameDraw();
 		return true;
 	}
-	struct Item *item = layoutFind(&point);
+	struct Item *item = listFind(&layout.main, &point);
 	if (!item) return false;
 	if (!gameAvail(item->card)) return gameReveal(item->card);
 	if (button.clicks % 2 == 0) {
@@ -358,7 +275,7 @@ static bool mouseButtonUp(SDL_MouseButtonEvent button) {
 	(void)button;
 	if (!layout.dragItem.card) return false;
 	for (uint dest = 0; dest < StacksLen; ++dest) {
-		if (SDL_HasIntersection(&layout.dragItem.rect, &layout.stacks[dest])) {
+		if (SDL_HasIntersection(&layout.dragItem.rect, &stackRects[dest])) {
 			if (gameMove(dest, layout.dragItem.card)) break;
 		}
 	}
@@ -379,11 +296,9 @@ static SDL_Texture *textures[Cards_Count];
 
 static void renderList(const struct List *list) {
 	for (uint i = 0; i < list->len; ++i) {
-		SDL_RenderCopy(
-			render,
-			textures[list->items[i].texture],
-			NULL, &list->items[i].rect
-		);
+		int tex = list->items[i].card;
+		if (tex < 0) tex = backTexture;
+		SDL_RenderCopy(render, textures[tex], NULL, &list->items[i].rect);
 	}
 }
 
@@ -451,19 +366,14 @@ int main(void) {
 	Cards_Free(cards);
 
 	srand(time(NULL));
-	layout.backTexture = Cards_Back1 + randUniform(12);
+	backTexture = Cards_Back1 + randUniform(12);
 	gameDeal();
 
 	for (;;) {
-		layoutClear();
-		layoutStock();
-		layoutWaste();
-		layoutFoundations();
-		layoutTableau();
+		updateLayout();
 
 		SDL_SetRenderDrawColor(render, 0x00, 0xAA, 0x55, 0xFF);
 		SDL_RenderClear(render);
-		renderList(&layout.base);
 		renderList(&layout.main);
 		renderList(&layout.drag);
 		SDL_RenderPresent(render);