Resizing works.

This commit is contained in:
Murilo Pereira 2011-06-19 19:36:29 -03:00
parent 561b4ba599
commit 893f18a7e0
10 changed files with 266 additions and 204 deletions

View File

@ -8,8 +8,7 @@
void card_malloc(struct card **card) {
if (!(*card = malloc(sizeof(**card)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
tty_solitaire_generic_error(errno, __FILE__, __LINE__);
}
frame_malloc(&((*card)->frame));
}

View File

@ -1,16 +1,25 @@
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include "common.h"
char *tty_solitaire_error_message(int errno, char *file, int line) {
char *message = malloc(sizeof(ERROR_MESSAGE_BUFFER_SIZE));
bool term_size_ok() {
int lines, columns;
getmaxyx(stdscr, lines, columns);
return(lines >= MIN_TERM_LINES && columns >= MIN_TERM_COLS);
}
void tty_solitaire_generic_error(int errno, char *file, int line) {
char message[TTY_SOLITAIRE_BUFSIZ];
snprintf(message,
ERROR_MESSAGE_BUFFER_SIZE,
"%s: %s (%s:%d)\n",
TTY_SOLITAIRE_BUFSIZ,
"%s: %s (%s:%d)",
program_name,
strerror(errno),
file,
line - 1);
return(message);
fprintf(stderr, "%s\n", message);
exit(errno);
}

View File

@ -1,8 +1,17 @@
#ifndef TTY_SOLITAIRE_COMMON_H
#define TTY_SOLITAIRE_COMMON_H
#include <stdbool.h>
#define MIN_TERM_LINES 28
#define MIN_TERM_COLS 57
#define TTY_SOLITAIRE_BUFSIZ 100
#define SMALL_TERM_MSG "Please increase your terminal size to at least 57x28 or press q to quit."
extern const char *program_name;
#define ERROR_MESSAGE_BUFFER_SIZE 100
char *tty_solitaire_error_message(int, char *, int);
void tty_solitaire_generic_error(int, char *, int);
bool term_size_ok();
#endif

View File

@ -11,8 +11,7 @@
void cursor_malloc(struct cursor **cursor) {
if (!(*cursor = malloc(sizeof(**cursor)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
tty_solitaire_generic_error(errno, __FILE__, __LINE__);
}
(*cursor)->window = newwin(1, 1, CURSOR_BEGIN_Y, CURSOR_BEGIN_X);
}

View File

@ -8,8 +8,7 @@
void deck_malloc(struct deck **deck) {
if (!(*deck = malloc(sizeof(**deck)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
tty_solitaire_generic_error(errno, __FILE__, __LINE__);
}
stack_malloc(&((*deck)->stock));
stack_malloc(&((*deck)->waste_pile));

View File

@ -8,8 +8,7 @@
void frame_malloc(struct frame **frame) {
if (!(*frame = malloc(sizeof(**frame)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
tty_solitaire_generic_error(errno, __FILE__, __LINE__);
}
(*frame)->window = newwin(FRAME_HEIGHT, FRAME_WIDTH, 0, 0);
}

View File

@ -149,8 +149,7 @@ static void shuffle_deck(struct deck *deck) {
int random;
if (!(card = malloc(NUMBER_OF_CARDS * sizeof(*card)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
tty_solitaire_generic_error(errno, __FILE__, __LINE__);
}
for (int i = 0; i < NUMBER_OF_CARDS; i++) {
card[i] = stack_pop(&(deck->stock));

View File

@ -1,4 +1,5 @@
#include <stdlib.h>
#include <ncurses.h>
#include <assert.h>
#include "keyboard.h"
@ -7,6 +8,18 @@
#include "game.h"
#include "cursor.h"
#include "gui.h"
#include "common.h"
static void handle_term_resize() {
clear();
refresh();
if (term_size_ok()) {
draw_deck(deck);
draw_cursor(cursor);
} else {
mvprintw(1, 1, SMALL_TERM_MSG);
}
}
/* FIXME: this function does not work on stacks with no marked cards.
* In that case it returns the stack's length. */
@ -35,12 +48,11 @@ static void unmark_cards(struct stack *stack) {
static void handle_card_movement(struct cursor *cursor) {
struct stack **origin = cursor_stack(cursor);
int option;
int key;
if (cursor_on_invalid_spot(cursor) || stack_empty(*origin)) {
return;
}
if (maneuvre_stack(*origin)) {
erase_stack(*origin);
card_mark((*origin)->card);
@ -51,8 +63,136 @@ static void handle_card_movement(struct cursor *cursor) {
cursor_mark(cursor);
draw_cursor(cursor);
while (1) {
switch (option = getch()) {
for (;;) {
if ((key = getch()) == 'q' || key == 'Q') {
endwin();
exit(0);
}
if (term_size_ok()) {
switch (key) {
case 'h':
case 'j':
case 'k':
case 'l':
case KEY_LEFT:
case KEY_DOWN:
case KEY_UP:
case KEY_RIGHT:
erase_cursor(cursor);
cursor_move(cursor, cursor_direction(key));
draw_cursor(cursor);
break;
case 'm':
if (origin == cursor_stack(cursor) && maneuvre_stack(*origin)) {
for (struct stack *i = *origin; i && i->next; i = i->next) {
if (i->next->card->face == EXPOSED &&
(i->card->frame->begin_y - i->next->card->frame->begin_y) > 1) {
erase_stack(*origin);
card_mark(i->next->card);
draw_stack(*origin);
break;
}
}
}
break;
case 'n':
if (origin == cursor_stack(cursor) && maneuvre_stack(*origin)) {
for (struct stack *i = (*origin)->next; i; i = i->next) {
if (i->next) {
if ((i->card->frame->begin_y - i->next->card->frame->begin_y) > 1) {
erase_stack(*origin);
card_unmark(i->card);
draw_stack(*origin);
break;
}
} else {
if (i->card->frame->begin_y == (MANEUVRE_BEGIN_Y + 1)) {
erase_stack(*origin);
card_unmark(i->card);
draw_stack(*origin);
break;
}
}
}
}
break;
case KEY_SPACEBAR:;
/* http://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg259382.html */
struct stack **destination = cursor_stack(cursor);
int _marked_cards_count = marked_cards_count(*origin);
if (maneuvre_stack(*origin) && _marked_cards_count > 0) {
erase_stack(*origin);
unmark_cards(*origin);
draw_stack(*origin);
}
if (destination) {
erase_stack(*origin);
erase_cursor(cursor);
if (_marked_cards_count > 1 &&
maneuvre_stack(*origin) &&
maneuvre_stack(*destination)) {
struct stack *block = *origin;
for (int i = 1; i < _marked_cards_count; block = block->next, i++)
;
if (valid_move(block, *destination)) {
move_block(origin, destination, _marked_cards_count);
}
} else {
if (valid_move(*origin, *destination)) {
if (maneuvre_stack(*destination)) {
cursor->y++;
}
move_card(origin, destination);
}
}
draw_stack(*origin);
draw_stack(*destination);
if (maneuvre_stack(*origin) && *origin == *destination) {
erase_cursor(cursor);
cursor->y--;
}
}
cursor_unmark(cursor);
draw_cursor(cursor);
return;
case KEY_ESCAPE:
if (cursor_stack(cursor) == origin && maneuvre_stack(*origin)) {
erase_cursor(cursor);
cursor->y--;
}
if (marked_cards_count(*origin) > 0) {
erase_stack(*origin);
unmark_cards(*origin);
draw_stack(*origin);
}
if (cursor->marked) {
cursor_unmark(cursor);
draw_cursor(cursor);
}
return;
case KEY_RESIZE:
handle_term_resize();
break;
case 'q':
case 'Q':
endwin();
game_end();
exit(0);
}
} else if (key == KEY_RESIZE) {
handle_term_resize();
}
}
}
void keyboard_event(int key) {
if (key == 'q' || key == 'Q') {
endwin();
game_end();
exit(0);
}
if (term_size_ok()) {
switch (key) {
case 'h':
case 'j':
case 'k':
@ -62,151 +202,46 @@ static void handle_card_movement(struct cursor *cursor) {
case KEY_UP:
case KEY_RIGHT:
erase_cursor(cursor);
cursor_move(cursor, cursor_direction(option));
cursor_move(cursor, cursor_direction(key));
draw_cursor(cursor);
break;
case 'm':
if (origin == cursor_stack(cursor) && maneuvre_stack(*origin)) {
for (struct stack *i = *origin; i && i->next; i = i->next) {
if (i->next->card->face == EXPOSED &&
(i->card->frame->begin_y - i->next->card->frame->begin_y) > 1) {
erase_stack(*origin);
card_mark(i->next->card);
draw_stack(*origin);
break;
}
}
}
break;
case 'n':
if (origin == cursor_stack(cursor) && maneuvre_stack(*origin)) {
for (struct stack *i = (*origin)->next; i; i = i->next) {
if (i->next) {
if ((i->card->frame->begin_y - i->next->card->frame->begin_y) > 1) {
erase_stack(*origin);
card_unmark(i->card);
draw_stack(*origin);
break;
case KEY_SPACEBAR:
if (cursor_on_stock(cursor)) {
if (stack_empty(deck->stock)) {
if (game.passes_through_deck_left >= 1) {
while (!stack_empty(deck->waste_pile)) {
move_card(&(deck->waste_pile), &(deck->stock));
card_cover(deck->stock->card);
}
} else {
if (i->card->frame->begin_y == (MANEUVRE_BEGIN_Y + 1)) {
erase_stack(*origin);
card_unmark(i->card);
draw_stack(*origin);
break;
}
}
}
}
break;
case KEY_SPACEBAR:;
/* http://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg259382.html */
struct stack **destination = cursor_stack(cursor);
int _marked_cards_count = marked_cards_count(*origin);
if (maneuvre_stack(*origin) && _marked_cards_count > 0) {
erase_stack(*origin);
unmark_cards(*origin);
draw_stack(*origin);
}
if (destination) {
erase_stack(*origin);
erase_cursor(cursor);
if (_marked_cards_count > 1 &&
maneuvre_stack(*origin) &&
maneuvre_stack(*destination)) {
struct stack *block = *origin;
for (int i = 1; i < _marked_cards_count; block = block->next, i++)
;
if (valid_move(block, *destination)) {
move_block(origin, destination, _marked_cards_count);
draw_stack(deck->stock);
draw_stack(deck->waste_pile);
}
} else {
if (valid_move(*origin, *destination)) {
if (maneuvre_stack(*destination)) {
cursor->y++;
}
move_card(origin, destination);
}
}
draw_stack(*origin);
draw_stack(*destination);
if (maneuvre_stack(*origin) && *origin == *destination) {
erase_cursor(cursor);
cursor->y--;
}
}
cursor_unmark(cursor);
draw_cursor(cursor);
return;
case KEY_ESCAPE:
if (cursor_stack(cursor) == origin && maneuvre_stack(*origin)) {
erase_cursor(cursor);
cursor->y--;
}
if (marked_cards_count(*origin) > 0) {
erase_stack(*origin);
unmark_cards(*origin);
draw_stack(*origin);
}
if (cursor->marked) {
cursor_unmark(cursor);
draw_cursor(cursor);
}
return;
case 'q':
case 'Q':
endwin();
game_end();
exit(0);
}
}
}
void keyboard_event(int key) {
switch (key) {
case 'h':
case 'j':
case 'k':
case 'l':
case KEY_LEFT:
case KEY_DOWN:
case KEY_UP:
case KEY_RIGHT:
erase_cursor(cursor);
cursor_move(cursor, cursor_direction(key));
draw_cursor(cursor);
break;
case KEY_SPACEBAR:
if (cursor_on_stock(cursor)) {
if (stack_empty(deck->stock)) {
if (game.passes_through_deck_left >= 1) {
while (!stack_empty(deck->waste_pile)) {
move_card(&(deck->waste_pile), &(deck->stock));
card_cover(deck->stock->card);
move_card(&(deck->stock), &(deck->waste_pile));
if (stack_empty(deck->stock)) {
game.passes_through_deck_left--;
}
card_expose(deck->waste_pile->card);
erase_stack(deck->waste_pile);
draw_stack(deck->stock);
draw_stack(deck->waste_pile);
}
} else {
move_card(&(deck->stock), &(deck->waste_pile));
if (stack_empty(deck->stock)) {
game.passes_through_deck_left--;
struct card *card;
if (cursor_stack(cursor) &&
(card = (*cursor_stack(cursor))->card)->face == COVERED) {
card_expose(card);
draw_card(card);
} else {
handle_card_movement(cursor);
}
card_expose(deck->waste_pile->card);
erase_stack(deck->waste_pile);
draw_stack(deck->stock);
draw_stack(deck->waste_pile);
}
} else {
struct card *card;
if (cursor_stack(cursor) &&
(card = (*cursor_stack(cursor))->card)->face == COVERED) {
card_expose(card);
draw_card(card);
} else {
handle_card_movement(cursor);
}
break;
case KEY_RESIZE:
handle_term_resize();
break;
}
break;
} else if (key == KEY_RESIZE) {
handle_term_resize();
}
}

View File

@ -10,8 +10,7 @@
void stack_malloc(struct stack **stack) {
if (!(*stack = malloc(sizeof(**stack)))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
tty_solitaire_generic_error(errno, __FILE__, __LINE__);
}
card_malloc(&((*stack)->card));
}

View File

@ -4,7 +4,6 @@
#include <getopt.h>
#include <errno.h>
#include "gui.h"
#include "game.h"
#include "keyboard.h"
#include "common.h"
@ -12,35 +11,9 @@
const char *program_name;
struct game game;
void draw_greeting() {
mvprintw(8, 26, "Welcome to tty-solitaire.");
mvprintw(10, 23, "Move with the arrow keys or hjkl.");
mvprintw(11, 19, "Use the space bar to mark and move cards.");
mvprintw(12, 16, "After marking a card you can use m to increase ");
mvprintw(13, 17, "and n to decrease the number of marked cards.");
mvprintw(15, 19, "Press the space bar to play or q to quit.");
}
void usage(const char *program_name) {
printf("usage: %s [-v|--version] [-h|--help] [-p|--passes=NUMBER]\n", program_name);
printf(" -v, --version Show version\n");
printf(" -h, --help Show this message\n");
printf(" -p, --passes Number of passes through the deck\n");
}
void version() {
FILE *version_file;
char version_string[6];
if (!(version_file = fopen("VERSION", "rb"))) {
fprintf(stderr, tty_solitaire_error_message(errno, __FILE__, __LINE__));
exit(errno);
}
fread(version_string, 1, 5, version_file);
version_string[5] = '\0';
printf("%s\n", version_string);
fclose(version_file);
}
void version();
void usage(const char *);
void draw_greeting();
int main(int argc, char *argv[]) {
int option;
@ -83,31 +56,44 @@ int main(int argc, char *argv[]) {
init_pair(3, COLOR_WHITE, COLOR_BLUE);
init_pair(4, COLOR_WHITE, COLOR_GREEN);
draw_greeting();
int key;
do {
switch (key = getch()) {
case KEY_SPACEBAR:
clear();
refresh();
game_init(&game, passes_through_deck);
break;
case 'q':
case 'Q':
while (!term_size_ok()) {
clear();
mvprintw(1, 1, SMALL_TERM_MSG);
refresh();
if ((key = getch()) == 'q' || key == 'Q') {
endwin();
return(0);
}
} while (key != KEY_SPACEBAR);
}
do {
clear();
draw_greeting();
refresh();
for (;;) {
if ((key = getch()) == 'q' || key == 'Q') {
endwin();
game_end();
exit(0);
} else {
keyboard_event(key);
return(0);
}
if (term_size_ok()) {
clear();
draw_greeting();
refresh();
if (key == KEY_SPACEBAR) {
game_init(&game, passes_through_deck);
break;
}
} else if (key == KEY_RESIZE) {
clear();
mvprintw(1, 1, SMALL_TERM_MSG);
refresh();
}
}
do {
keyboard_event(getch());
} while (!game_won());
endwin();
@ -116,3 +102,32 @@ int main(int argc, char *argv[]) {
return(0);
}
void draw_greeting() {
mvprintw(8, 26, "Welcome to tty-solitaire.");
mvprintw(10, 23, "Move with the arrow keys or hjkl.");
mvprintw(11, 19, "Use the space bar to mark and move cards.");
mvprintw(12, 16, "After marking a card you can use m to increase ");
mvprintw(13, 17, "and n to decrease the number of marked cards.");
mvprintw(15, 19, "Press the space bar to play or q to quit.");
}
void usage(const char *program_name) {
printf("usage: %s [-v|--version] [-h|--help] [-p|--passes=NUMBER]\n", program_name);
printf(" -v, --version Show version\n");
printf(" -h, --help Show this message\n");
printf(" -p, --passes Number of passes through the deck\n");
}
void version() {
FILE *version_file;
char version_string[6];
if (!(version_file = fopen("VERSION", "rb"))) {
tty_solitaire_generic_error(errno, __FILE__, __LINE__);
}
fread(version_string, 1, 5, version_file);
version_string[5] = '\0';
printf("%s\n", version_string);
fclose(version_file);
}