2011-02-06 05:44:45 +00:00
|
|
|
#include <stdio.h>
|
2010-04-13 02:42:21 +00:00
|
|
|
#include <stdlib.h>
|
2011-06-06 03:42:23 +00:00
|
|
|
#include <stdbool.h>
|
2010-04-13 02:42:21 +00:00
|
|
|
#include <malloc.h>
|
2011-02-06 05:44:45 +00:00
|
|
|
#include <errno.h>
|
2010-04-13 02:42:21 +00:00
|
|
|
#include <time.h>
|
2011-05-29 20:12:52 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
2011-06-03 05:48:26 +00:00
|
|
|
#include "game.h"
|
|
|
|
#include "card.h"
|
|
|
|
#include "stack.h"
|
|
|
|
#include "deck.h"
|
2011-06-03 06:22:48 +00:00
|
|
|
#include "draw.h"
|
2011-06-03 05:48:26 +00:00
|
|
|
#include "cursor.h"
|
2011-05-08 23:20:22 +00:00
|
|
|
#include "common.h"
|
2010-04-13 02:42:21 +00:00
|
|
|
|
2011-06-03 05:48:26 +00:00
|
|
|
static int foundation_begin_x(int x) {
|
2011-05-29 20:12:52 +00:00
|
|
|
switch (x) {
|
2011-06-03 06:27:53 +00:00
|
|
|
case 0: return(FOUNDATION_0_BEGIN_X);
|
|
|
|
case 1: return(FOUNDATION_1_BEGIN_X);
|
|
|
|
case 2: return(FOUNDATION_2_BEGIN_X);
|
|
|
|
case 3: return(FOUNDATION_3_BEGIN_X);
|
2011-05-31 05:44:16 +00:00
|
|
|
default:
|
2011-06-03 06:09:14 +00:00
|
|
|
endwin();
|
2011-06-04 20:15:12 +00:00
|
|
|
game_end();
|
2011-05-31 05:44:16 +00:00
|
|
|
assert(false && "invalid stack");
|
2011-05-29 20:12:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:48:26 +00:00
|
|
|
static int maneuvre_begin_x(int x) {
|
2011-05-29 20:12:52 +00:00
|
|
|
switch (x) {
|
2011-06-03 06:27:53 +00:00
|
|
|
case 0: return(MANEUVRE_0_BEGIN_X);
|
|
|
|
case 1: return(MANEUVRE_1_BEGIN_X);
|
|
|
|
case 2: return(MANEUVRE_2_BEGIN_X);
|
|
|
|
case 3: return(MANEUVRE_3_BEGIN_X);
|
|
|
|
case 4: return(MANEUVRE_4_BEGIN_X);
|
|
|
|
case 5: return(MANEUVRE_5_BEGIN_X);
|
|
|
|
case 6: return(MANEUVRE_6_BEGIN_X);
|
2011-05-31 05:44:16 +00:00
|
|
|
default:
|
2011-06-03 06:09:14 +00:00
|
|
|
endwin();
|
2011-06-04 20:15:12 +00:00
|
|
|
game_end();
|
2011-05-31 05:44:16 +00:00
|
|
|
assert(false && "maneuvre_begin_x called x < 0 || x > 6");
|
2011-05-29 20:12:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-03 05:48:26 +00:00
|
|
|
static bool waste_pile_stack(struct stack *stack) {
|
|
|
|
return((stack->card->frame->begin_y == WASTE_PILE_BEGIN_Y) &&
|
2011-05-29 20:12:52 +00:00
|
|
|
(stack->card->frame->begin_x == WASTE_PILE_BEGIN_X));
|
2011-05-08 02:09:39 +00:00
|
|
|
}
|
|
|
|
|
2011-06-03 05:48:26 +00:00
|
|
|
static bool foundation_stack(struct stack *stack) {
|
|
|
|
return(stack->card->frame->begin_y == FOUNDATION_BEGIN_Y &&
|
2011-05-29 20:12:52 +00:00
|
|
|
(stack->card->frame->begin_x == FOUNDATION_0_BEGIN_X ||
|
|
|
|
stack->card->frame->begin_x == FOUNDATION_1_BEGIN_X ||
|
|
|
|
stack->card->frame->begin_x == FOUNDATION_2_BEGIN_X ||
|
|
|
|
stack->card->frame->begin_x == FOUNDATION_3_BEGIN_X));
|
2011-05-08 02:09:39 +00:00
|
|
|
}
|
|
|
|
|
2011-06-08 05:36:46 +00:00
|
|
|
bool stock_stack(struct stack *stack) {
|
|
|
|
return((stack->card->frame->begin_y == STOCK_BEGIN_Y) &&
|
|
|
|
(stack->card->frame->begin_x == STOCK_BEGIN_X));
|
|
|
|
}
|
|
|
|
|
2011-05-01 05:05:35 +00:00
|
|
|
bool maneuvre_stack(struct stack *stack) {
|
2011-06-03 05:48:26 +00:00
|
|
|
return(stack->card->frame->begin_y >= MANEUVRE_BEGIN_Y &&
|
|
|
|
(stack->card->frame->begin_x == MANEUVRE_0_BEGIN_X ||
|
|
|
|
stack->card->frame->begin_x == MANEUVRE_1_BEGIN_X ||
|
|
|
|
stack->card->frame->begin_x == MANEUVRE_2_BEGIN_X ||
|
|
|
|
stack->card->frame->begin_x == MANEUVRE_3_BEGIN_X ||
|
|
|
|
stack->card->frame->begin_x == MANEUVRE_4_BEGIN_X ||
|
|
|
|
stack->card->frame->begin_x == MANEUVRE_5_BEGIN_X ||
|
|
|
|
stack->card->frame->begin_x == MANEUVRE_6_BEGIN_X));
|
2011-05-08 02:09:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool valid_move(struct stack *origin, struct stack *destination) {
|
2011-06-01 05:18:53 +00:00
|
|
|
if (origin->card->face == EXPOSED) {
|
|
|
|
if (stock_stack(origin) && waste_pile_stack(destination)) {
|
2011-05-08 02:09:39 +00:00
|
|
|
return(true);
|
2011-06-01 05:18:53 +00:00
|
|
|
} else if (foundation_stack(destination)) {
|
2011-06-06 04:57:52 +00:00
|
|
|
if (stack_empty(destination)) {
|
2011-06-01 05:18:53 +00:00
|
|
|
if (origin->card->value == ACE) {
|
|
|
|
return(true);
|
|
|
|
}
|
2011-06-01 14:43:16 +00:00
|
|
|
} else if (origin->card->suit == destination->card->suit &&
|
|
|
|
origin->card->value == destination->card->value + 1) {
|
|
|
|
return(true);
|
2011-06-01 05:18:53 +00:00
|
|
|
}
|
|
|
|
} else if (maneuvre_stack(destination)) {
|
2011-06-06 04:57:52 +00:00
|
|
|
if (stack_empty(destination)) {
|
2011-06-01 05:18:53 +00:00
|
|
|
if (origin->card->value == KING) {
|
|
|
|
return(true);
|
|
|
|
}
|
2011-06-01 14:43:16 +00:00
|
|
|
} else if (destination->card->face == EXPOSED &&
|
|
|
|
(origin->card->suit + destination->card->suit) % 2 == 1 &&
|
2011-06-01 05:18:53 +00:00
|
|
|
origin->card->value + 1 == destination->card->value) {
|
|
|
|
return(true);
|
|
|
|
}
|
2011-05-08 02:09:39 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-01 05:18:53 +00:00
|
|
|
|
|
|
|
return(false);
|
2011-02-17 00:26:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void move_card(struct stack **origin, struct stack **destination) {
|
2011-05-29 18:19:00 +00:00
|
|
|
struct card *tmp;
|
2011-06-06 04:57:52 +00:00
|
|
|
if ((tmp = stack_pop(origin))) {
|
2011-05-29 18:19:00 +00:00
|
|
|
int destination_y = (*destination)->card->frame->begin_y;
|
|
|
|
int destination_x = (*destination)->card->frame->begin_x;
|
2011-06-06 04:57:52 +00:00
|
|
|
if (!stack_empty(*destination) && maneuvre_stack(*destination)) {
|
2011-05-29 18:19:00 +00:00
|
|
|
destination_y++;
|
|
|
|
}
|
2011-06-06 04:57:52 +00:00
|
|
|
stack_push(destination, tmp);
|
2011-06-06 05:16:54 +00:00
|
|
|
frame_set((*destination)->card->frame, destination_y, destination_x);
|
2011-02-17 00:26:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-06 02:08:08 +00:00
|
|
|
void move_block(struct stack **origin, struct stack **destination, int block_size) {
|
|
|
|
struct stack *tmp;
|
2011-06-06 04:57:52 +00:00
|
|
|
stack_malloc(&tmp);
|
|
|
|
stack_init(tmp);
|
2011-06-06 02:08:08 +00:00
|
|
|
for (int i = 0; i < block_size; i++) {
|
2011-06-06 04:57:52 +00:00
|
|
|
stack_push(&tmp, stack_pop(origin));
|
2011-06-06 02:08:08 +00:00
|
|
|
}
|
|
|
|
for (int i = 0; i < block_size; i++) {
|
|
|
|
move_card(&tmp, destination);
|
|
|
|
}
|
2011-06-06 04:57:52 +00:00
|
|
|
if (stack_length(*destination) > 1) {
|
2011-06-06 02:08:08 +00:00
|
|
|
cursor->y += block_size;
|
|
|
|
}
|
2011-06-06 04:57:52 +00:00
|
|
|
stack_free(tmp);
|
2011-06-06 02:08:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-06 06:45:53 +00:00
|
|
|
static void fill_deck(struct deck *deck) {
|
2010-04-13 02:42:21 +00:00
|
|
|
struct card *card[NUMBER_OF_CARDS];
|
|
|
|
|
2011-06-01 14:43:16 +00:00
|
|
|
for (int i = ACE; i <= KING; i++) {
|
2011-05-29 20:12:52 +00:00
|
|
|
for (int j = DIAMONDS; j <= CLUBS; j++) {
|
2011-06-01 14:43:16 +00:00
|
|
|
int index = 4 * (i - ACE) + j;
|
2011-06-06 04:57:52 +00:00
|
|
|
card_malloc(&(card[index]));
|
|
|
|
card_set(card[index], i, j, COVERED, 1, 1);
|
|
|
|
stack_push(&(deck->stock), card[index]);
|
2011-05-29 20:12:52 +00:00
|
|
|
}
|
2010-04-13 02:42:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 06:45:53 +00:00
|
|
|
static void shuffle_deck(struct deck *deck) {
|
2011-05-29 18:19:00 +00:00
|
|
|
struct card **card, tmp;
|
2010-04-13 02:42:21 +00:00
|
|
|
int random;
|
|
|
|
|
2011-05-29 18:19:00 +00:00
|
|
|
if (!(card = malloc(NUMBER_OF_CARDS * sizeof(*card)))) {
|
2011-05-08 23:20:22 +00:00
|
|
|
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
|
2011-02-06 05:44:45 +00:00
|
|
|
exit(errno);
|
|
|
|
}
|
2010-04-13 02:42:21 +00:00
|
|
|
for (int i = 0; i < NUMBER_OF_CARDS; i++) {
|
2011-06-06 04:57:52 +00:00
|
|
|
card[i] = stack_pop(&(deck->stock));
|
2010-04-13 02:42:21 +00:00
|
|
|
}
|
|
|
|
srand(time(NULL));
|
|
|
|
for (int i = 0; i < NUMBER_OF_CARDS - 1; i++) {
|
|
|
|
random = i + (rand() % (NUMBER_OF_CARDS) - i);
|
2011-05-29 18:19:00 +00:00
|
|
|
tmp = *card[i];
|
|
|
|
*card[i] = (*card[random]);
|
|
|
|
*card[random] = tmp;
|
2010-04-13 02:42:21 +00:00
|
|
|
}
|
|
|
|
for (int i = 0; i < NUMBER_OF_CARDS; i++) {
|
2011-06-06 04:57:52 +00:00
|
|
|
stack_push(&(deck->stock), card[i]);
|
2010-04-13 02:42:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-06 06:45:53 +00:00
|
|
|
static void deal_cards(struct deck *deck) {
|
2011-05-29 20:12:52 +00:00
|
|
|
for (int i = 0; i < 7; i++) {
|
|
|
|
move_card(&(deck->stock), &(deck->maneuvre[i]));
|
2011-06-06 04:57:52 +00:00
|
|
|
card_expose(deck->maneuvre[i]->card);
|
2011-05-29 20:12:52 +00:00
|
|
|
for (int j = i + 1; j < 7; j++) {
|
|
|
|
move_card(&(deck->stock), &(deck->maneuvre[j]));
|
|
|
|
}
|
|
|
|
}
|
2010-04-13 02:42:21 +00:00
|
|
|
}
|
|
|
|
|
2011-06-08 05:36:46 +00:00
|
|
|
void game_init(struct game *game, int passes_through_deck) {
|
2011-06-06 05:21:50 +00:00
|
|
|
cursor_malloc(&cursor);
|
|
|
|
cursor_init(cursor);
|
2011-06-06 05:04:03 +00:00
|
|
|
deck_malloc(&deck);
|
|
|
|
deck_init(deck);
|
2011-02-06 02:15:21 +00:00
|
|
|
|
2011-05-31 05:44:16 +00:00
|
|
|
/* Setting initial stacks' coordinates. */
|
2011-06-06 05:16:54 +00:00
|
|
|
frame_set(deck->stock->card->frame, STOCK_BEGIN_Y, STOCK_BEGIN_X);
|
|
|
|
frame_set(deck->waste_pile->card->frame, WASTE_PILE_BEGIN_Y, WASTE_PILE_BEGIN_X);
|
2011-06-03 05:48:26 +00:00
|
|
|
for (int i = 0; i < FOUNDATION_STACKS_NUMBER; i++) {
|
2011-06-06 05:16:54 +00:00
|
|
|
frame_set(deck->foundation[i]->card->frame, FOUNDATION_BEGIN_Y, foundation_begin_x(i));
|
2011-05-31 05:44:16 +00:00
|
|
|
}
|
2011-06-03 05:48:26 +00:00
|
|
|
for (int i = 0; i < MANEUVRE_STACKS_NUMBER; i++) {
|
2011-06-06 05:16:54 +00:00
|
|
|
frame_set(deck->maneuvre[i]->card->frame, MANEUVRE_BEGIN_Y, maneuvre_begin_x(i));
|
2011-05-31 05:44:16 +00:00
|
|
|
}
|
|
|
|
|
2011-02-06 02:15:21 +00:00
|
|
|
fill_deck(deck);
|
|
|
|
shuffle_deck(deck);
|
|
|
|
deal_cards(deck);
|
|
|
|
|
|
|
|
draw_cursor(cursor);
|
2011-02-06 02:22:16 +00:00
|
|
|
draw_deck(deck);
|
2011-06-08 05:36:46 +00:00
|
|
|
|
|
|
|
game->passes_through_deck_left = passes_through_deck;
|
2010-04-13 02:42:21 +00:00
|
|
|
}
|
|
|
|
|
2011-06-04 20:15:12 +00:00
|
|
|
void game_end() {
|
2011-06-06 05:21:50 +00:00
|
|
|
cursor_free(cursor);
|
2011-06-06 05:04:03 +00:00
|
|
|
deck_free(deck);
|
2010-04-13 02:42:21 +00:00
|
|
|
}
|
2011-06-06 03:42:23 +00:00
|
|
|
|
|
|
|
bool game_won() {
|
2011-06-06 04:57:52 +00:00
|
|
|
return(stack_length(deck->foundation[0]) == 13 &&
|
|
|
|
stack_length(deck->foundation[1]) == 13 &&
|
|
|
|
stack_length(deck->foundation[2]) == 13 &&
|
|
|
|
stack_length(deck->foundation[3]) == 13);
|
2011-06-06 03:42:23 +00:00
|
|
|
}
|