diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | layout.h | 113 | ||||
-rw-r--r-- | sol.c | 170 |
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); |