tty-solitaire/src/game.c

204 lines
6.0 KiB
C
Raw Normal View History

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <errno.h>
#include <time.h>
#include <assert.h>
#include "display.h"
2011-05-08 23:38:36 +00:00
#include "curses.h"
2011-05-08 23:20:22 +00:00
#include "common.h"
#include "game.h"
int foundation_begin_x(int x) {
switch (x) {
case 0: return(FOUNDATION_0_BEGIN_X); break;
case 1: return(FOUNDATION_1_BEGIN_X); break;
case 2: return(FOUNDATION_2_BEGIN_X); break;
case 3: return(FOUNDATION_3_BEGIN_X); break;
2011-05-31 05:44:16 +00:00
default:
end_curses();
end_game();
assert(false && "invalid stack");
}
}
int maneuvre_begin_x(int x) {
switch (x) {
case 0: return(MANEUVRE_0_BEGIN_X); break;
case 1: return(MANEUVRE_1_BEGIN_X); break;
case 2: return(MANEUVRE_2_BEGIN_X); break;
case 3: return(MANEUVRE_3_BEGIN_X); break;
case 4: return(MANEUVRE_4_BEGIN_X); break;
case 5: return(MANEUVRE_5_BEGIN_X); break;
case 6: return(MANEUVRE_6_BEGIN_X); break;
2011-05-31 05:44:16 +00:00
default:
end_curses();
end_game();
assert(false && "maneuvre_begin_x called x < 0 || x > 6");
}
}
2011-05-08 02:09:39 +00:00
bool stock_stack(struct stack *stack) {
return(stack && stack->card && stack->card->frame &&
(stack->card->frame->begin_y == STOCK_BEGIN_Y) &&
(stack->card->frame->begin_x == STOCK_BEGIN_X));
2011-05-08 02:09:39 +00:00
}
bool waste_pile_stack(struct stack *stack) {
return(stack && stack->card && stack->card->frame &&
(stack->card->frame->begin_y == WASTE_PILE_BEGIN_Y) &&
(stack->card->frame->begin_x == WASTE_PILE_BEGIN_X));
2011-05-08 02:09:39 +00:00
}
bool foundation_stack(struct stack *stack) {
return(stack && stack->card && stack->card->frame &&
stack->card->frame->begin_y == FOUNDATION_BEGIN_Y &&
(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
}
bool maneuvre_stack(struct stack *stack) {
2011-05-08 02:09:39 +00:00
return(stack && stack->card && stack->card->frame &&
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) {
if (origin->card->face == EXPOSED) {
if (stock_stack(origin) && waste_pile_stack(destination)) {
2011-05-08 02:09:39 +00:00
return(true);
} else if (foundation_stack(destination)) {
if (empty(destination)) {
if (origin->card->value == ACE) {
return(true);
}
} else if (origin->card->suit == destination->card->suit &&
origin->card->value == destination->card->value + 1) {
return(true);
}
} else if (maneuvre_stack(destination)) {
if (empty(destination)) {
if (origin->card->value == KING) {
return(true);
}
} else if (destination->card->face == EXPOSED &&
(origin->card->suit + destination->card->suit) % 2 == 1 &&
origin->card->value + 1 == destination->card->value) {
return(true);
}
2011-05-08 02:09:39 +00:00
}
}
return(false);
2011-02-17 00:26:18 +00:00
}
void move_card(struct stack **origin, struct stack **destination) {
struct card *tmp;
if ((tmp = pop(origin))) {
int destination_y = (*destination)->card->frame->begin_y;
int destination_x = (*destination)->card->frame->begin_x;
if (!empty(*destination) && maneuvre_stack(*destination)) {
destination_y++;
}
push(destination, tmp);
set_frame((*destination)->card->frame, destination_y, destination_x);
2011-02-17 00:26:18 +00:00
}
}
2011-02-06 06:45:53 +00:00
static void fill_deck(struct deck *deck) {
struct card *card[NUMBER_OF_CARDS];
for (int i = ACE; i <= KING; i++) {
for (int j = DIAMONDS; j <= CLUBS; j++) {
int index = 4 * (i - ACE) + j;
allocate_card(&(card[index]));
set_card(card[index], i, j, COVERED, 1, 1);
push(&(deck->stock), card[index]);
}
}
}
2011-02-06 06:45:53 +00:00
static void shuffle_deck(struct deck *deck) {
struct card **card, tmp;
int random;
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__));
exit(errno);
}
for (int i = 0; i < NUMBER_OF_CARDS; i++) {
card[i] = pop(&(deck->stock));
}
srand(time(NULL));
for (int i = 0; i < NUMBER_OF_CARDS - 1; i++) {
random = i + (rand() % (NUMBER_OF_CARDS) - i);
tmp = *card[i];
*card[i] = (*card[random]);
*card[random] = tmp;
}
for (int i = 0; i < NUMBER_OF_CARDS; i++) {
push(&(deck->stock), card[i]);
}
}
2011-02-06 06:45:53 +00:00
static void deal_cards(struct deck *deck) {
for (int i = 0; i < 7; i++) {
move_card(&(deck->stock), &(deck->maneuvre[i]));
expose_card(deck->maneuvre[i]->card);
for (int j = i + 1; j < 7; j++) {
move_card(&(deck->stock), &(deck->maneuvre[j]));
}
}
}
void greet_player() {
2011-04-30 20:40:22 +00:00
mvprintw(10, 27, "Welcome to tty-solitaire.");
mvprintw(11, 8, "Move with \u2190\u2191\u2192\u2193 or hjkl. Use the space bar to mark and move cards.");
mvprintw(12, 19, "Press the space bar to play or q to quit.");
}
void initialize_game() {
clear_screen();
allocate_cursor(&cursor);
initialize_cursor(cursor);
allocate_deck(&deck);
initialize_deck(deck);
2011-05-31 05:44:16 +00:00
/* Setting initial stacks' coordinates. */
set_frame(deck->stock->card->frame, STOCK_BEGIN_Y, STOCK_BEGIN_X);
set_frame(deck->waste_pile->card->frame, WASTE_PILE_BEGIN_Y, WASTE_PILE_BEGIN_X);
for (int i = 0; i < 4; i++) {
set_frame(deck->foundation[i]->card->frame, FOUNDATION_BEGIN_Y, foundation_begin_x(i));
}
for (int i = 0; i < 7; i++) {
set_frame(deck->maneuvre[i]->card->frame, MANEUVRE_BEGIN_Y, maneuvre_begin_x(i));
}
fill_deck(deck);
shuffle_deck(deck);
deal_cards(deck);
draw_cursor(cursor);
2011-02-06 02:22:16 +00:00
draw_deck(deck);
}
2011-02-10 01:50:24 +00:00
void end_game() {
2011-02-14 02:10:47 +00:00
free_deck(deck);
2011-05-09 05:04:38 +00:00
free_cursor(cursor);
}