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