C-ifying project.

This commit is contained in:
Murilo Pereira
2011-05-31 03:03:13 -03:00
parent 57a38c7152
commit 1c63b767f6
38 changed files with 47 additions and 49 deletions

64
src/card.c Normal file
View File

@@ -0,0 +1,64 @@
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <errno.h>
#include "card.h"
#include "common.h"
void allocate_card(struct card **card) {
if (!(*card = malloc(sizeof(**card)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
}
allocate_frame(&((*card)->frame));
}
void initialize_card(struct card *card) {
initialize_frame(card->frame);
card->value = NO_VALUE;
card->suit = NO_SUIT;
card->face = NO_FACE;
}
struct card *duplicate_card(struct card *card) {
struct card *new_card;
allocate_card(&new_card);
set_card(new_card,
card->value,
card->suit,
card->face,
card->frame->begin_y,
card->frame->begin_x);
return(new_card);
}
void free_card(struct card *card) {
if (card) {
free_frame(card->frame);
}
free(card);
}
void set_card(struct card *card,
enum value value,
enum suit suit,
enum face face,
int begin_y,
int begin_x) {
set_frame(card->frame, begin_y, begin_x);
card->value = value;
card->suit = suit;
card->face = face;
}
void expose_card(struct card *card) {
card->face = EXPOSED;
}
void cover_card(struct card *card) {
card->face = COVERED;
}

52
src/card.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef CARD_H
#define CARD_H
#include "frame.h"
enum value {
NO_VALUE = -1,
TWO = 2,
THREE = 3,
FOUR = 4,
FIVE = 5,
SIX = 6,
SEVEN = 7,
EIGHT = 8,
NINE = 9,
TEN = 10,
JACK = 11,
QUEEN = 12,
KING = 13,
ACE = 14
};
enum suit {
NO_SUIT = -1,
DIAMONDS = 0,
SPADES = 1,
HEARTS = 2,
CLUBS = 3
};
enum face {
NO_FACE = -1,
COVERED = 0,
EXPOSED = 1
};
struct card {
struct frame *frame;
enum value value;
enum suit suit;
enum face face;
};
void allocate_card(struct card **);
void initialize_card(struct card *);
struct card *duplicate_card(struct card *);
void free_card(struct card *);
void set_card(struct card *, enum value, enum suit, enum face, int, int);
void expose_card(struct card *);
void cover_card(struct card *);
#endif

16
src/common.c Normal file
View File

@@ -0,0 +1,16 @@
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "common.h"
char *tty_solitaire_error_message(int errno, char *file, int line) {
char *message = malloc(sizeof(ERROR_MESSAGE_BUFFER_SIZE));
snprintf(message,
ERROR_MESSAGE_BUFFER_SIZE,
"%s: %s (%s:%d)\n",
program_name,
strerror(errno),
file,
line - 1);
return(message);
}

8
src/common.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef COMMON_H
#define COMMON_H
extern const char *program_name;
#define ERROR_MESSAGE_BUFFER_SIZE 100
char *tty_solitaire_error_message(int, char *, int);
#endif

31
src/curses.c Normal file
View File

@@ -0,0 +1,31 @@
#include <stdio.h>
#include <ncurses.h>
#include <locale.h>
#include "curses.h"
void initialize_curses() {
setlocale(LC_ALL, "en_US.utf-8"); /* Support unicode characters. */
initscr();
raw(); /* Disable line buffers. */
noecho();
keypad(stdscr, TRUE); /* Enable arrow keys. */
start_color(); /* I want colors. */
curs_set(FALSE); /* Invisible cursor. */
set_escdelay(0);
assume_default_colors(COLOR_WHITE, COLOR_GREEN);
init_pair(1, COLOR_BLACK, COLOR_WHITE);
init_pair(2, COLOR_RED, COLOR_WHITE);
init_pair(3, COLOR_WHITE, COLOR_BLUE);
init_pair(4, COLOR_WHITE, COLOR_GREEN);
}
void end_curses() {
endwin();
puts("Game finished.");
}
void clear_screen() {
clear();
refresh();
}

8
src/curses.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef TTY_SOLITAIRE_CURSES_H
#define TTY_SOLITAIRE_CURSES_H
void initialize_curses();
void end_curses();
void clear_screen();
#endif

100
src/cursor.c Normal file
View File

@@ -0,0 +1,100 @@
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <errno.h>
#include <ncurses.h>
#include "display.h"
#include "game.h"
#include "cursor.h"
#include "common.h"
void allocate_cursor(struct cursor **cursor) {
if (!(*cursor = malloc(sizeof(**cursor)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
} else {
(*cursor)->window = NULL;
}
}
void initialize_cursor(struct cursor *cursor) {
cursor->window = newwin(0, 0, cursor->y, cursor->x);
cursor->x = CURSOR_BEGIN_X;
cursor->y = CURSOR_BEGIN_Y;
cursor->marked = false;
}
void free_cursor(struct cursor *cursor) {
if (cursor) {
delwin(cursor->window);
}
free(cursor);
}
void mark_cursor(struct cursor *cursor) {
cursor->marked = true;
}
void unmark_cursor(struct cursor *cursor) {
cursor->marked = false;
}
void move_cursor(struct cursor *cursor, enum movement movement) {
switch (movement) {
case LEFT:
if (cursor->x > CURSOR_BEGIN_X) {
erase_cursor(cursor);
cursor->x = cursor->x - 8;
if (cursor->y > CURSOR_BEGIN_Y) {
move_cursor(cursor, UP);
move_cursor(cursor, DOWN);
}
}
break;
case DOWN:
if (cursor->y == CURSOR_BEGIN_Y) {
erase_cursor(cursor);
switch (cursor->x - 3) {
case MANEUVRE_0_BEGIN_X:
cursor->y = cursor->y + 7 + length(deck->maneuvre[0]);
break;
case MANEUVRE_1_BEGIN_X:
cursor->y = cursor->y + 7 + length(deck->maneuvre[1]);
break;
case MANEUVRE_2_BEGIN_X:
cursor->y = cursor->y + 7 + length(deck->maneuvre[2]);
break;
case MANEUVRE_3_BEGIN_X:
cursor->y = cursor->y + 7 + length(deck->maneuvre[3]);
break;
case MANEUVRE_4_BEGIN_X:
cursor->y = cursor->y + 7 + length(deck->maneuvre[4]);
break;
case MANEUVRE_5_BEGIN_X:
cursor->y = cursor->y + 7 + length(deck->maneuvre[5]);
break;
case MANEUVRE_6_BEGIN_X:
cursor->y = cursor->y + 7 + length(deck->maneuvre[6]);
break;
}
}
break;
case RIGHT:
if (cursor->x < 49) {
erase_cursor(cursor);
cursor->x = cursor->x + 8;
if (cursor->y > CURSOR_BEGIN_Y) {
move_cursor(cursor, UP);
move_cursor(cursor, DOWN);
}
}
break;
case UP:
if (cursor->y > 1) {
erase_cursor(cursor);
cursor->y = CURSOR_BEGIN_Y;
}
break;
}
}

45
src/cursor.h Normal file
View File

@@ -0,0 +1,45 @@
#ifndef CURSOR_H
#define CURSOR_H
#include <stdbool.h>
#include "deck.h"
#define CURSOR_BEGIN_X 4
#define CURSOR_BEGIN_Y 7
#define CURSOR_INVALID_SPOT_X 20
#define CURSOR_INVALID_SPOT_Y 7
#define CURSOR_STOCK_X 4
#define CURSOR_WASTE_PILE_X 12
#define CURSOR_FOUNDATION_0_X 28
#define CURSOR_FOUNDATION_1_X 36
#define CURSOR_FOUNDATION_2_X 44
#define CURSOR_FOUNDATION_3_X 52
#define CURSOR_MANEUVRE_0_X 4
#define CURSOR_MANEUVRE_1_X 12
#define CURSOR_MANEUVRE_2_X 20
#define CURSOR_MANEUVRE_3_X 28
#define CURSOR_MANEUVRE_4_X 36
#define CURSOR_MANEUVRE_5_X 44
#define CURSOR_MANEUVRE_6_X 52
struct cursor {
WINDOW *window;
int x;
int y;
bool marked;
};
enum movement { LEFT, DOWN, UP, RIGHT };
extern struct deck *deck;
void allocate_cursor(struct cursor **);
void initialize_cursor(struct cursor *);
void free_cursor(struct cursor *);
void mark_cursor(struct cursor *);
void unmark_cursor(struct cursor *);
void move_cursor(struct cursor *, enum movement);
#endif

48
src/deck.c Normal file
View File

@@ -0,0 +1,48 @@
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <errno.h>
#include "deck.h"
#include "common.h"
void allocate_deck(struct deck **deck) {
if (!(*deck = malloc(sizeof(**deck)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
}
allocate_stack(&((*deck)->stock));
allocate_stack(&((*deck)->waste_pile));
for (int i = 0; i < 4; i++) {
allocate_stack(&((*deck)->foundation[i]));
}
for (int i = 0; i < 7; i++) {
allocate_stack(&((*deck)->maneuvre[i]));
}
}
void initialize_deck(struct deck *deck) {
initialize_stack(deck->stock);
initialize_stack(deck->waste_pile);
for (int i = 0; i < 4; i++) {
initialize_stack(deck->foundation[i]);
}
for (int i = 0; i < 7; i++) {
initialize_stack(deck->maneuvre[i]);
}
}
void free_deck(struct deck *deck) {
if (deck) {
free_stack(deck->stock);
free_stack(deck->waste_pile);
for (int i = 0; i < 4; i++) {
free_stack(deck->foundation[i]);
}
for (int i = 0; i < 7; i++) {
free_stack(deck->maneuvre[i]);
}
}
free(deck);
}

17
src/deck.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef DECK_H
#define DECK_H
#include "stack.h"
struct deck {
struct stack *stock;
struct stack *waste_pile;
struct stack *foundation[4];
struct stack *maneuvre[7];
};
void allocate_deck(struct deck **);
void initialize_deck(struct deck *);
void free_deck(struct deck *);
#endif

157
src/display.c Normal file
View File

@@ -0,0 +1,157 @@
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <errno.h>
#include <ncurses.h>
#include "game.h"
#include "display.h"
#include "common.h"
static char *card_suit(enum suit suit) {
char *card_suit;
if (!(card_suit = malloc(4 * sizeof(*card_suit)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
}
switch(suit) {
case DIAMONDS: strcpy(card_suit, DIAMONDS_SYMBOL); break;
case SPADES: strcpy(card_suit, SPADES_SYMBOL); break;
case HEARTS: strcpy(card_suit, HEARTS_SYMBOL); break;
case CLUBS: strcpy(card_suit, CLUBS_SYMBOL); break;
default: strcpy(card_suit, "?");
}
return(card_suit);
}
static char *card_value(enum value value) {
char *card_value;
if (!(card_value = malloc(2 * sizeof(*card_value)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
}
switch(value) {
case TWO: card_value = "2"; break;
case THREE: card_value = "3"; break;
case FOUR: card_value = "4"; break;
case FIVE: card_value = "5"; break;
case SIX: card_value = "6"; break;
case SEVEN: card_value = "7"; break;
case EIGHT: card_value = "8"; break;
case NINE: card_value = "9"; break;
case TEN: card_value = "10"; break;
case JACK: card_value = "J"; break;
case QUEEN: card_value = "Q"; break;
case KING: card_value = "K"; break;
case ACE: card_value = "A"; break;
default: card_value = "?";
}
return(card_value);
}
void erase_card(struct card *card) {
werase(card->frame->window);
wbkgd(card->frame->window, WHITE_ON_GREEN);
wrefresh(card->frame->window);
}
void erase_stack(struct stack *stack) {
if (maneuvre_stack(stack)) {
for (; stack; stack = stack->next) {
erase_card(stack->card);
}
} else {
erase_card(stack->card);
}
}
void draw_value(struct card *card) {
mvwprintw(card->frame->window, 0, 0, card_value(card->value));
mvwprintw(card->frame->window,
4,
6 - (strlen(card_value(card->value)) - 1),
card_value(card->value));
}
void draw_suit(struct card *card) {
if (card->suit % 2 == 0) {
wattron(card->frame->window, COLOR_PAIR(RED_ON_WHITE));
} else {
wattron(card->frame->window, COLOR_PAIR(BLACK_ON_WHITE));
}
mvwprintw(card->frame->window, 0, 1 + (strlen(card_value(card->value) + 1)),
card_suit(card->suit));
mvwprintw(card->frame->window, 4, 5 - (strlen(card_value(card->value) + 1)),
card_suit(card->suit));
if (card->suit % 2 == 0) {
wattroff(card->frame->window, COLOR_PAIR(RED_ON_WHITE));
} else {
wattroff(card->frame->window, COLOR_PAIR(BLACK_ON_WHITE));
}
}
void draw_front(struct card *card) {
wbkgd(card->frame->window, COLOR_PAIR(BLACK_ON_WHITE));
draw_value(card);
draw_suit(card);
}
void draw_back(struct card *card) {
wbkgd(card->frame->window, COLOR_PAIR(WHITE_ON_BLUE));
}
void draw_card(struct card *card) {
if (card->face == EXPOSED) {
draw_front(card);
} else {
draw_back(card);
}
wrefresh(card->frame->window);
}
void draw_stack(struct stack *stack) {
erase_stack(stack);
if (empty(stack)) {
box(stack->card->frame->window, 0, 0);
wrefresh(stack->card->frame->window);
} else {
if (maneuvre_stack(stack)) {
struct stack *reversed_stack = reverse(stack);
for (struct stack *i = reversed_stack; i; i = i->next) {
draw_card(i->card);
}
} else {
draw_card(stack->card);
}
}
}
void draw_deck(struct deck *deck) {
draw_stack(deck->stock);
draw_stack(deck->waste_pile);
for (int i = 0; i < 4; i++) {
draw_stack(deck->foundation[i]);
}
for (int i = 0; i < 7; i++) {
draw_stack(deck->maneuvre[i]);
}
}
void draw_cursor(struct cursor *cursor) {
if (cursor->marked) {
mvwaddch(cursor->window, cursor->y, cursor->x, '@');
} else {
mvwaddch(cursor->window, cursor->y, cursor->x, '*');
}
wrefresh(cursor->window);
}
void erase_cursor(struct cursor *cursor) {
mvwdelch(cursor->window, cursor->y, cursor->x);
}

32
src/display.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef DISPLAY_H
#define DISPLAY_H
#include "card.h"
#include "stack.h"
#include "deck.h"
#include "cursor.h"
#define EMPTY_STACKS_NUMBER 13
#define DIAMONDS_SYMBOL "\u2666"
#define SPADES_SYMBOL "\u2660"
#define HEARTS_SYMBOL "\u2665"
#define CLUBS_SYMBOL "\u2663"
#define BLACK_ON_WHITE 1
#define RED_ON_WHITE 2
#define WHITE_ON_BLUE 3
#define WHITE_ON_GREEN 4
void erase_stack(struct stack *);
void draw_value(struct card *);
void draw_suit(struct card *);
void draw_front(struct card *);
void draw_back(struct card *);
void draw_card(struct card *);
void draw_stack(struct stack *);
void draw_deck(struct deck *);
void draw_cursor(struct cursor *);
void erase_cursor(struct cursor *);
#endif

42
src/frame.c Normal file
View File

@@ -0,0 +1,42 @@
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <errno.h>
#include "frame.h"
#include "common.h"
void allocate_frame(struct frame **frame) {
if (!(*frame = malloc(sizeof(**frame)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
}
(*frame)->window = newwin(FRAME_HEIGHT, FRAME_WIDTH, 0, 0);
}
void initialize_frame(struct frame *frame) {
frame->begin_y = 0;
frame->begin_x = 0;
}
struct frame *duplicate_frame(struct frame *frame) {
struct frame *new_frame;
allocate_frame(&new_frame);
set_frame(new_frame, frame->begin_y, frame->begin_x);
return(new_frame);
}
void free_frame(struct frame *frame) {
if (frame) {
delwin(frame->window);
}
free(frame);
}
void set_frame(struct frame *frame, int begin_y, int begin_x) {
frame->begin_y = begin_y;
frame->begin_x = begin_x;
mvwin(frame->window, begin_y, begin_x);
}

21
src/frame.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef FRAME_H
#define FRAME_H
#include <ncurses.h>
#define FRAME_WIDTH 7
#define FRAME_HEIGHT 5
struct frame {
WINDOW *window;
int begin_y;
int begin_x;
};
void allocate_frame(struct frame **);
void initialize_frame(struct frame *);
struct frame *duplicate_frame(struct frame *);
void free_frame(struct frame *);
void set_frame(struct frame *, int, int);
#endif

205
src/game.c Normal file
View File

@@ -0,0 +1,205 @@
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <assert.h>
#include "display.h"
#include "curses.h"
#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;
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;
default:
end_curses();
end_game();
assert(false && "maneuvre_begin_x called x < 0 || x > 6");
}
}
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));
}
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));
}
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));
}
bool maneuvre_stack(struct stack *stack) {
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));
}
bool valid_move(struct stack *origin, struct stack *destination) {
if (stock_stack(origin)) {
if (waste_pile_stack(destination)) {
return(true);
} else {
return(false);
}
} else if (waste_pile_stack(origin)) {
if (foundation_stack(destination) || maneuvre_stack(destination)) {
return(true);
} else {
return(false);
}
} else if (foundation_stack(origin)) {
if ((foundation_stack(destination) && origin != destination) || maneuvre_stack(destination)) {
return(true);
} else {
return(false);
}
} else if (maneuvre_stack(origin)) {
if ((maneuvre_stack(destination) && origin != destination) || foundation_stack(destination)) {
return(true);
} else {
return(false);
}
} else {
return(false);
}
}
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);
}
}
static void fill_deck(struct deck *deck) {
struct card *card[NUMBER_OF_CARDS];
for (int i = TWO; i <= ACE; i++) {
for (int j = DIAMONDS; j <= CLUBS; j++) {
int index = 4 * (i - TWO) + j;
allocate_card(&(card[index]));
set_card(card[index], i, j, COVERED, 1, 1);
push(&(deck->stock), card[index]);
}
}
}
static void shuffle_deck(struct deck *deck) {
struct card **card, tmp;
int random;
if (!(card = malloc(NUMBER_OF_CARDS * sizeof(*card)))) {
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]);
}
}
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() {
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);
/* 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);
draw_deck(deck);
}
void end_game() {
free_deck(deck);
free_cursor(cursor);
}

43
src/game.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef GAME_H
#define GAME_H
#include "stack.h"
#include "deck.h"
#include "cursor.h"
#define NUMBER_OF_CARDS 52
#define STOCK_BEGIN_X 1
#define STOCK_BEGIN_Y 1
#define WASTE_PILE_BEGIN_X 9
#define WASTE_PILE_BEGIN_Y 1
#define FOUNDATION_BEGIN_Y 1
#define FOUNDATION_0_BEGIN_X 25
#define FOUNDATION_1_BEGIN_X 33
#define FOUNDATION_2_BEGIN_X 41
#define FOUNDATION_3_BEGIN_X 49
#define MANEUVRE_BEGIN_Y 9
#define MANEUVRE_0_BEGIN_X 1
#define MANEUVRE_1_BEGIN_X 9
#define MANEUVRE_2_BEGIN_X 17
#define MANEUVRE_3_BEGIN_X 25
#define MANEUVRE_4_BEGIN_X 33
#define MANEUVRE_5_BEGIN_X 41
#define MANEUVRE_6_BEGIN_X 49
struct deck *deck;
struct cursor *cursor;
int foundation_begin_x(int);
int maneuvre_begin_x(int);
bool valid_move(struct stack *, struct stack *);
bool maneuvre_stack(struct stack *);
void move_card(struct stack **, struct stack **);
void greet_player();
void initialize_game();
void end_game();
#endif

143
src/keyboard.c Normal file
View File

@@ -0,0 +1,143 @@
#include <stdlib.h>
#include <assert.h>
#include "card.h"
#include "game.h"
#include "display.h"
#include "curses.h"
#include "keyboard.h"
static bool cursor_on_stock(struct cursor *cursor) {
return((cursor->x == CURSOR_BEGIN_X) && (cursor->y == CURSOR_BEGIN_Y));
}
static struct stack **cursor_stack(struct cursor *cursor) {
if (cursor->y == CURSOR_BEGIN_Y) {
switch (cursor->x) {
case CURSOR_STOCK_X: return(&(deck->stock));
case CURSOR_WASTE_PILE_X: return(&(deck->waste_pile));
case CURSOR_FOUNDATION_0_X: return(&(deck->foundation[0]));
case CURSOR_FOUNDATION_1_X: return(&(deck->foundation[1]));
case CURSOR_FOUNDATION_2_X: return(&(deck->foundation[2]));
case CURSOR_FOUNDATION_3_X: return(&(deck->foundation[3]));
default: assert(false && "invalid stack");
}
} else {
switch (cursor->x) {
case CURSOR_MANEUVRE_0_X: return(&(deck->maneuvre[0]));
case CURSOR_MANEUVRE_1_X: return(&(deck->maneuvre[1]));
case CURSOR_MANEUVRE_2_X: return(&(deck->maneuvre[2]));
case CURSOR_MANEUVRE_3_X: return(&(deck->maneuvre[3]));
case CURSOR_MANEUVRE_4_X: return(&(deck->maneuvre[4]));
case CURSOR_MANEUVRE_5_X: return(&(deck->maneuvre[5]));
case CURSOR_MANEUVRE_6_X: return(&(deck->maneuvre[6]));
default: assert(false && "invalid stack");
}
}
}
static bool cursor_on_invalid_spot(struct cursor *cursor) {
return(cursor->x == CURSOR_INVALID_SPOT_X &&
cursor->y == CURSOR_INVALID_SPOT_Y);
}
static void handle_stock_event() {
if (!empty(deck->stock)) {
move_card(&(deck->stock), &(deck->waste_pile));
expose_card(deck->waste_pile->card);
draw_stack(deck->stock);
draw_stack(deck->waste_pile);
}
}
static void handle_card_movement(struct cursor *cursor) {
struct stack **origin = cursor_stack(cursor);
struct stack **destination;
int option;
if (cursor_on_invalid_spot(cursor) || empty(*origin)) {
return;
}
mark_cursor(cursor);
draw_cursor(cursor);
while (1) {
switch (option = getch()) {
case KEY_ESCAPE:
if (cursor->marked) {
unmark_cursor(cursor);
draw_cursor(cursor);
}
break;
case 'h':
case KEY_LEFT:
move_cursor(cursor, LEFT);
draw_cursor(cursor);
break;
case 'j':
case KEY_DOWN:
move_cursor(cursor, DOWN);
draw_cursor(cursor);
break;
case 'k':
case KEY_UP:
move_cursor(cursor, UP);
draw_cursor(cursor);
break;
case 'l':
case KEY_RIGHT:
move_cursor(cursor, RIGHT);
draw_cursor(cursor);
break;
case KEY_SPACEBAR:
destination = cursor_stack(cursor);
if (valid_move(*origin, *destination)) {
erase_stack(*origin);
move_card(origin, destination);
draw_stack(*origin);
draw_stack(*destination);
}
unmark_cursor(cursor);
draw_cursor(cursor);
return;
case 'q':
case 'Q':
end_curses();
end_game();
exit(0);
}
}
}
void handle_keyboard_event(int key) {
switch (key) {
case 'h':
case KEY_LEFT:
move_cursor(cursor, LEFT);
draw_cursor(cursor);
break;
case 'j':
case KEY_DOWN:
move_cursor(cursor, DOWN);
draw_cursor(cursor);
break;
case 'k':
case KEY_UP:
move_cursor(cursor, UP);
draw_cursor(cursor);
break;
case 'l':
case KEY_RIGHT:
move_cursor(cursor, RIGHT);
draw_cursor(cursor);
break;
case KEY_SPACEBAR:
if (cursor_on_stock(cursor)) {
handle_stock_event();
} else {
handle_card_movement(cursor);
}
break;
}
}

15
src/keyboard.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef KEYBOARD_H
#define KEYBOARD_H
#include "deck.h"
#include "cursor.h"
#define KEY_SPACEBAR 32
#define KEY_ESCAPE 27
extern struct deck *deck;
extern struct cursor *cursor;
void handle_keyboard_event();
#endif

122
src/stack.c Normal file
View File

@@ -0,0 +1,122 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <malloc.h>
#include <string.h>
#include <errno.h>
#include "stack.h"
#include "common.h"
void allocate_stack(struct stack **stack) {
if (!(*stack = malloc(sizeof(**stack)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
}
allocate_card(&((*stack)->card));
}
void initialize_stack(struct stack *stack) {
initialize_card(stack->card);
stack->next = NULL;
}
struct stack *duplicate_stack(struct stack *stack) {
struct stack *iterator = stack;
struct stack *tmp_stack, *new_stack;
allocate_stack(&new_stack);
allocate_stack(&tmp_stack);
initialize_stack(new_stack);
initialize_stack(tmp_stack);
for (iterator = stack; iterator; iterator = iterator->next) {
push(&tmp_stack, duplicate_card(iterator->card));
}
while (!empty(tmp_stack)) {
push(&new_stack, (pop(&tmp_stack)));
}
free_stack(tmp_stack);
return(new_stack);
}
void free_stack(struct stack *stack) {
struct stack *tmp;
for (; stack; stack = tmp) {
tmp = stack->next;
free_card(stack->card);
free(stack);
}
}
bool empty(struct stack *stack) {
return(stack->card->value == NO_VALUE &&
stack->card->suit == NO_SUIT &&
stack->card->face == NO_FACE &&
!stack->next);
}
int length(struct stack *stack) {
int length = 0;
if (!empty(stack)) {
for (length = 1; stack->next; stack = stack->next, length++)
;
}
return(length);
}
void push(struct stack **stack, struct card *card) {
if (card) {
if (empty(*stack)) {
(*stack)->card = card;
} else {
/* Allocating by hand because stack#allocate_stack would
* have allocated an unwanted card object. */
struct stack *new_stack = malloc(sizeof(*new_stack));
new_stack->card = card;
new_stack->next = (*stack);
*stack = new_stack;
}
}
}
struct card *pop(struct stack **stack) {
if(empty(*stack)) {
return(NULL);
} else {
struct card *popped_card = (*stack)->card;
if (length(*stack) == 1) {
/* Remembering the stack position before clearing it. */
int begin_y = (*stack)->card->frame->begin_y;
int begin_x = (*stack)->card->frame->begin_x;
allocate_card(&((*stack)->card));
/* An empty stack is a stack with a blank top card
* and with stack->next == NULL. */
set_card((*stack)->card, NO_VALUE, NO_SUIT, NO_FACE, begin_y, begin_x);
(*stack)->next = NULL;
} else {
struct stack *tmp = *stack;
*stack = (*stack)->next;
free(tmp);
}
return(popped_card);
}
}
struct stack *reverse(struct stack *stack) {
if (length(stack) > 1) {
struct stack *tmp_stack, *iterator;
allocate_stack(&tmp_stack);
initialize_stack(tmp_stack);
for (iterator = stack; iterator; iterator = iterator->next) {
push(&tmp_stack, iterator->card);
}
return(tmp_stack);
} else {
return(stack);
}
}

21
src/stack.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef STACK_H
#define STACK_H
#include "card.h"
struct stack {
struct card *card;
struct stack *next;
};
void allocate_stack(struct stack **);
void initialize_stack(struct stack *);
struct stack *duplicate_stack(struct stack *);
void free_stack(struct stack *);
bool empty(struct stack *);
int length(struct stack *);
void push(struct stack **, struct card *);
struct card *pop(struct stack **);
struct stack *reverse(struct stack *);
#endif

39
src/ttysolitaire.c Normal file
View File

@@ -0,0 +1,39 @@
#include <stdlib.h>
#include <ncurses.h>
#include "curses.h"
#include "game.h"
#include "keyboard.h"
const char *program_name;
int main(int argc, const char *argv[]) {
program_name = *argv;
int key;
initialize_curses();
greet_player();
while (key != KEY_SPACEBAR) {
switch (key = getch()) {
case KEY_SPACEBAR:
initialize_game();
break;
case 'q':
case 'Q':
end_curses();
exit(0);
}
}
while (1) {
if ((key = getch()) == 'q' || key == 'Q') {
end_curses();
end_game();
exit(0);
} else {
handle_keyboard_event(key);
}
}
return(0);
}