1 #include <assert.h>
2 #include <errno.h>
3 #include <stdbool.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <time.h>
7
8 #include "card.h"
9 #include "common.h"
10 #include "cursor.h"
11 #include "deck.h"
12 #include "game.h"
13 #include "gui.h"
14 #include "stack.h"
15
foundation_begin_x(int x)16 static int foundation_begin_x(int x) {
17 switch (x) {
18 case 0:
19 return (FOUNDATION_0_BEGIN_X);
20 case 1:
21 return (FOUNDATION_1_BEGIN_X);
22 case 2:
23 return (FOUNDATION_2_BEGIN_X);
24 case 3:
25 return (FOUNDATION_3_BEGIN_X);
26 default:
27 endwin();
28 game_end();
29 assert(false && "invalid stack");
30 }
31 }
32
maneuvre_begin_x(int x)33 static int maneuvre_begin_x(int x) {
34 switch (x) {
35 case 0:
36 return (MANEUVRE_0_BEGIN_X);
37 case 1:
38 return (MANEUVRE_1_BEGIN_X);
39 case 2:
40 return (MANEUVRE_2_BEGIN_X);
41 case 3:
42 return (MANEUVRE_3_BEGIN_X);
43 case 4:
44 return (MANEUVRE_4_BEGIN_X);
45 case 5:
46 return (MANEUVRE_5_BEGIN_X);
47 case 6:
48 return (MANEUVRE_6_BEGIN_X);
49 default:
50 endwin();
51 game_end();
52 assert(false && "maneuvre_begin_x called x < 0 || x > 6");
53 }
54 }
55
waste_pile_stack(struct stack * stack)56 static bool waste_pile_stack(struct stack *stack) {
57 return ((stack->card->frame->begin_y == WASTE_PILE_BEGIN_Y) &&
58 (stack->card->frame->begin_x == WASTE_PILE_BEGIN_X));
59 }
60
foundation_stack(struct stack * stack)61 static bool foundation_stack(struct stack *stack) {
62 return (stack->card->frame->begin_y == FOUNDATION_BEGIN_Y &&
63 (stack->card->frame->begin_x == FOUNDATION_0_BEGIN_X ||
64 stack->card->frame->begin_x == FOUNDATION_1_BEGIN_X ||
65 stack->card->frame->begin_x == FOUNDATION_2_BEGIN_X ||
66 stack->card->frame->begin_x == FOUNDATION_3_BEGIN_X));
67 }
68
stock_stack(struct stack * stack)69 bool stock_stack(struct stack *stack) {
70 return ((stack->card->frame->begin_y == STOCK_BEGIN_Y) &&
71 (stack->card->frame->begin_x == STOCK_BEGIN_X));
72 }
73
maneuvre_stack(struct stack * stack)74 bool maneuvre_stack(struct stack *stack) {
75 return (stack->card->frame->begin_y >= MANEUVRE_BEGIN_Y &&
76 (stack->card->frame->begin_x == MANEUVRE_0_BEGIN_X ||
77 stack->card->frame->begin_x == MANEUVRE_1_BEGIN_X ||
78 stack->card->frame->begin_x == MANEUVRE_2_BEGIN_X ||
79 stack->card->frame->begin_x == MANEUVRE_3_BEGIN_X ||
80 stack->card->frame->begin_x == MANEUVRE_4_BEGIN_X ||
81 stack->card->frame->begin_x == MANEUVRE_5_BEGIN_X ||
82 stack->card->frame->begin_x == MANEUVRE_6_BEGIN_X));
83 }
84
valid_move(struct stack * origin,struct stack * destination)85 bool valid_move(struct stack *origin, struct stack *destination) {
86 if (origin->card->face == EXPOSED) {
87 if (stock_stack(origin) && waste_pile_stack(destination)) {
88 return (true);
89 } else if (foundation_stack(destination)) {
90 if (stack_empty(destination)) {
91 if (origin->card->value == ACE) {
92 return (true);
93 }
94 } else if (origin->card->suit == destination->card->suit &&
95 origin->card->value == destination->card->value + 1) {
96 return (true);
97 }
98 } else if (maneuvre_stack(destination)) {
99 if (stack_empty(destination)) {
100 if (origin->card->value == KING) {
101 return (true);
102 }
103 } else if (destination->card->face == EXPOSED &&
104 (origin->card->suit + destination->card->suit) % 2 == 1 &&
105 origin->card->value + 1 == destination->card->value) {
106 return (true);
107 }
108 }
109 }
110
111 return (false);
112 }
113
move_card(struct stack ** origin,struct stack ** destination)114 void move_card(struct stack **origin, struct stack **destination) {
115 struct card *tmp;
116 if ((tmp = stack_pop(origin))) {
117 int destination_y = (*destination)->card->frame->begin_y;
118 int destination_x = (*destination)->card->frame->begin_x;
119 if (!stack_empty(*destination) && maneuvre_stack(*destination)) {
120 destination_y++;
121 }
122 stack_push(destination, tmp);
123 frame_set((*destination)->card->frame, destination_y, destination_x);
124 }
125 }
126
move_block(struct stack ** origin,struct stack ** destination,int block_size)127 void move_block(struct stack **origin, struct stack **destination,
128 int block_size) {
129 struct stack *tmp;
130 stack_malloc(&tmp);
131 stack_init(tmp);
132 for (int i = 0; i < block_size; i++) {
133 stack_push(&tmp, stack_pop(origin));
134 }
135 for (int i = 0; i < block_size; i++) {
136 move_card(&tmp, destination);
137 }
138 if (stack_length(*destination) > 1) {
139 cursor->y += block_size;
140 }
141 stack_free(tmp);
142 }
143
fill_deck(struct deck * deck)144 static void fill_deck(struct deck *deck) {
145 struct card *card[NUMBER_OF_CARDS];
146
147 for (int i = ACE; i <= KING; i++) {
148 for (int j = DIAMONDS; j <= CLUBS; j++) {
149 int index = 4 * (i - ACE) + j;
150 card_malloc(&(card[index]));
151 card_set(card[index], i, j, COVERED, 1, 1);
152 stack_push(&(deck->stock), card[index]);
153 }
154 }
155 }
156
shuffle_deck(struct deck * deck)157 static void shuffle_deck(struct deck *deck) {
158 struct card **card, tmp;
159 int random;
160
161 if (!(card = malloc(NUMBER_OF_CARDS * sizeof(*card)))) {
162 tty_solitaire_generic_error(errno, __FILE__, __LINE__);
163 }
164 for (int i = 0; i < NUMBER_OF_CARDS; i++) {
165 card[i] = stack_pop(&(deck->stock));
166 }
167 srand(time(NULL));
168 for (int i = 0; i < NUMBER_OF_CARDS; i++) {
169 random = rand() % (NUMBER_OF_CARDS);
170 tmp = *card[i];
171 *card[i] = (*card[random]);
172 *card[random] = tmp;
173 }
174 for (int i = 0; i < NUMBER_OF_CARDS; i++) {
175 stack_push(&(deck->stock), card[i]);
176 }
177 free(card);
178 }
179
deal_cards(struct deck * deck)180 static void deal_cards(struct deck *deck) {
181 for (int i = 0; i < MANEUVRE_STACKS_NUMBER; i++) {
182 move_card(&(deck->stock), &(deck->maneuvre[i]));
183 card_expose(deck->maneuvre[i]->card);
184 for (int j = i + 1; j < MANEUVRE_STACKS_NUMBER; j++) {
185 move_card(&(deck->stock), &(deck->maneuvre[j]));
186 }
187 }
188 }
189
game_init(struct game * game,int passes_through_deck,int four_color_deck)190 void game_init(struct game *game, int passes_through_deck,
191 int four_color_deck) {
192 cursor_malloc(&cursor);
193 cursor_init(cursor);
194 deck_malloc(&deck);
195 deck_init(deck);
196
197 /* Setting initial stacks' coordinates. */
198 frame_set(deck->stock->card->frame, STOCK_BEGIN_Y, STOCK_BEGIN_X);
199 frame_set(deck->waste_pile->card->frame, WASTE_PILE_BEGIN_Y,
200 WASTE_PILE_BEGIN_X);
201 for (int i = 0; i < FOUNDATION_STACKS_NUMBER; i++) {
202 frame_set(deck->foundation[i]->card->frame, FOUNDATION_BEGIN_Y,
203 foundation_begin_x(i));
204 }
205 for (int i = 0; i < MANEUVRE_STACKS_NUMBER; i++) {
206 frame_set(deck->maneuvre[i]->card->frame, MANEUVRE_BEGIN_Y,
207 maneuvre_begin_x(i));
208 }
209
210 game->four_color_deck = four_color_deck;
211
212 fill_deck(deck);
213 shuffle_deck(deck);
214 deal_cards(deck);
215
216 draw_cursor(cursor);
217 draw_deck(deck);
218
219 game->passes_through_deck_left = passes_through_deck;
220 }
221
game_end()222 void game_end() {
223 cursor_free(cursor);
224 deck_free(deck);
225 }
226
game_won()227 bool game_won() {
228 // If any card in the maneuvre stacks is covered, game is not won.
229 for (int i = 0; i < MANEUVRE_STACKS_NUMBER; i++) {
230 for (struct stack *j = deck->maneuvre[i]; j != NULL; j = j->next) {
231 if (j->card->face == COVERED) {
232 return (false);
233 }
234 }
235 }
236
237 // If the stock pile or the waste pile aren't empty, game is not won.
238 if (!stack_empty(deck->stock) || !stack_empty(deck->waste_pile)) {
239 return (false);
240 }
241
242 return (true);
243 }
244