From 1169992d50ce930143efe2851d02e7dfa0304e29 Mon Sep 17 00:00:00 2001 From: Ian C Date: Fri, 21 Dec 2018 11:27:26 +0000 Subject: Split code up into separate objects. --- klondike.c | 513 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 513 insertions(+) create mode 100644 klondike.c (limited to 'klondike.c') diff --git a/klondike.c b/klondike.c new file mode 100644 index 0000000..0a5b760 --- /dev/null +++ b/klondike.c @@ -0,0 +1,513 @@ +/* + + csol - CURSES solitaire + + Copyright (C) 2018 Ian Cowburn (ianc@noddybox.co.uk) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + ------------------------------------------------------------------------- + + Klondike + +*/ +#include + +#include "deck.h" +#include "pile.h" +#include "util.h" + +static int CanCardSitOnTop(Card card, Card on) +{ + int ret = FALSE; + + if (card.suit != NoSuit && on.suit != NoSuit) + { + if (card.value == on.value - 1) + { + switch(card.suit) + { + case Spade: + case Club: + ret = (on.suit == Heart || on.suit == Diamond); + break; + + case Heart: + case Diamond: + ret = (on.suit == Spade || on.suit == Club); + break; + + case NoSuit: + break; + } + } + } + + return ret; +} + +static int PutCardOnSuitPile(Pile *from, Pile *hearts, Pile *diamonds, + Pile *spades, Pile *clubs) +{ + Card c; + Pile *p; + int move = FALSE; + + c = TopOfPile(from); + + if (c.suit != NoSuit) + { + switch(c.suit) + { + case Heart: + p = hearts; + break; + case Diamond: + p = diamonds; + break; + case Spade: + p = spades; + break; + case Club: + p = clubs; + break; + default: + p = NULL; + break; + } + + if (p->no) + { + if (c.value == TopOfPile(p).value + 1) + { + move = TRUE; + } + } + else + { + if (c.value == 1 ) + { + move = TRUE; + } + } + + if (move) + { + MoveTopCard(from, p); + } + } + + return move; +} + +static void RevealCard(Pile *column_down, Pile *column_up) +{ + if (column_up->no == 0) + { + if (column_down->no) + { + InsertBottomOfPile(column_up, PopPile(column_down)); + } + } +} + +static void KlondikeHelp(void) +{ + static const char *text[] = + { + "Use the cursor keys to move the cursor around.", + "", + "Press RETURN to select a bunch of cards to move.", + "Press RETURN again when you are where you want to move the cards.", + "", + "Use space to draw the next set of cards.", + "", + "Use 'S' to move a card from the drawn cards to the current column.", + "", + "Use 'P' to put the current card on the suits piles.", + "If invalid it will attempt to move the card from the drawn pile.", + "", + "Press '1', '2', '3' or '4' to move the top card from the hearts, ", + "diamonds, spades or clubs suit pile respectively back onto the board.", + "", + "Press 'Q' to quit. You'll be asked if you want to see the cards.", + "", + "", + "Press SPACE to continue.", + NULL + }; + + int y = 2; + int f; + + erase(); + + for(f = 0; text[f]; f++) + { + Centre(y++, text[f]); + } + + refresh(); + + while(getch() != ' '); +} + +void Klondike(int draw) +{ + Deck deck; + Pile pile = {0}; + Pile turned = {0}; + Pile hearts = {0}; + Pile diamonds = {0}; + Pile clubs = {0}; + Pile spades = {0}; + Pile column_down[7] = {{0}}; + Pile column_up[7] = {{0}}; + int f; + int n; + int i; + int won = FALSE; + int quit = FALSE; + int show = FALSE; + int pos_x = 0; + int pos_y = 0; + int move_pos_x = -1; + int move_pos_y = -1; + + Init(deck); + Shuffle(deck); + + i = 0; + + for(f = 0; f < 7; f++) + { + for(n = 0; n < f; n++) + { + AddToPile(&column_down[f], deck[i++]); + } + + AddToPile(&column_up[f], deck[i++]); + } + + while(i < 52) + { + AddToPile(&pile, deck[i++]); + } + + while(!quit && !won) + { + Card c = {0}; + int key = 0; + + erase(); + + DrawCard(0, 0, TRUE, TopOfPile(&pile)); + DrawCard(0, 4, FALSE, TopOfPile(&turned)); + + DrawCard(0, 10, FALSE, TopOfPile(&hearts)); + DrawCard(0, 15, FALSE, TopOfPile(&diamonds)); + DrawCard(0, 20, FALSE, TopOfPile(&spades)); + DrawCard(0, 25, FALSE, TopOfPile(&clubs)); + + for(f = 0; f < 7; f++) + { + for(n = 0; n < column_down[f].no; n++) + { + DrawCard(2 + n, 1 + f * 5, TRUE, column_down[f].card[n]); + } + + for(n = 0; n < column_up[f].no; n++) + { + DrawCard(2 + column_down[f].no + n, 1 + f * 5, + FALSE, column_up[f].card[n]); + } + } + + if (move_pos_x != -1) + { + mvaddch(2 + column_down[move_pos_x].no + move_pos_y, + move_pos_x * 5, '*'); + mvaddch(2 + column_down[move_pos_x].no + move_pos_y, + move_pos_x * 5 + 4, '*'); + } + + if (!column_up[pos_x].no && !column_down[pos_x].no) + { + mvaddch(2, pos_x * 5, '>'); + mvaddch(2, pos_x * 5 + 4, '<'); + } + else + { + mvaddch(2 + column_down[pos_x].no + pos_y, pos_x * 5, '>'); + mvaddch(2 + column_down[pos_x].no + pos_y, pos_x * 5 + 4, '<'); + } + + if (hearts.no == 13 && diamonds.no == 13 && + spades.no == 13 && clubs.no == 13) + { + won = TRUE; + } + + refresh(); + + if (!won) + { + key = getch(); + } + + switch(key) + { + case ' ': + if (pile.no) + { + for(f = 0; f < draw; f++) + { + MoveTopCard(&pile, &turned); + } + } + else + { + SwapPile(&pile, &turned); + } + break; + + case 'S': + case 's': + c = TopOfPile(&turned); + + if (c.value == 13 && column_up[pos_x].no == 0 && + column_down[pos_x].no == 0) + { + MoveTopCard(&turned, &column_up[pos_x]); + } + else + { + if (CanCardSitOnTop(c, TopOfPile(&column_up[pos_x]))) + { + MoveTopCard(&turned, &column_up[pos_x]); + pos_y++; + } + } + break; + + case 'P': + case 'p': + if (PutCardOnSuitPile(&column_up[pos_x], + &hearts, &diamonds, &spades, &clubs)) + { + RevealCard(&column_down[pos_x], &column_up[pos_x]); + + pos_y--; + + if (pos_y < 0) + { + pos_y = 0; + } + } + else + { + PutCardOnSuitPile(&turned, &hearts, &diamonds, + &spades, &clubs); + } + break; + + case 'Q': + case 'q': + { + int k; + + quit = TRUE; + Centre(LINES-1, "Show cards?"); + refresh(); + k = getch(); + show = (k == 'y' || k == 'Y'); + break; + } + + case 10: + if (move_pos_x == -1) + { + move_pos_x = pos_x; + move_pos_y = pos_y; + } + else + { + int can_move = FALSE; + + if (column_up[move_pos_x].no && + column_up[move_pos_x].card[move_pos_y].value == 13 && + column_up[pos_x].no == 0 && column_down[pos_x].no == 0) + { + can_move = TRUE; + } + else + { + if (column_up[move_pos_x].no && + CanCardSitOnTop + (column_up[move_pos_x].card[move_pos_y], + TopOfPile(&column_up[pos_x]))) + { + can_move = TRUE; + } + } + + if (can_move) + { + Pile temp = {0}; + + while(column_up[move_pos_x].no > move_pos_y) + { + MoveTopCard(&column_up[move_pos_x], + &temp); + } + + while(temp.no) + { + MoveTopCard(&temp, + &column_up[pos_x]); + } + + RevealCard(&column_down[move_pos_x], + &column_up[move_pos_x]); + } + + move_pos_x = -1; + move_pos_y = -1; + } + break; + + case '1': + if (CanCardSitOnTop(TopOfPile(&hearts), + TopOfPile(&column_up[pos_x]))) + { + MoveTopCard(&hearts, &column_up[pos_x]); + } + break; + + case '2': + if (CanCardSitOnTop(TopOfPile(&diamonds), + TopOfPile(&column_up[pos_x]))) + { + MoveTopCard(&diamonds, &column_up[pos_x]); + } + break; + + case '3': + if (CanCardSitOnTop(TopOfPile(&spades), + TopOfPile(&column_up[pos_x]))) + { + MoveTopCard(&spades, &column_up[pos_x]); + } + break; + + case '4': + if (CanCardSitOnTop(TopOfPile(&clubs), + TopOfPile(&column_up[pos_x]))) + { + MoveTopCard(&clubs, &column_up[pos_x]); + } + break; + + case KEY_LEFT: + if (pos_x) + { + pos_x--; + pos_y = column_up[pos_x].no - 1; + + if (pos_y < 0) + { + pos_y = 0; + } + } + break; + + case KEY_RIGHT: + if (pos_x < 6) + { + pos_x++; + pos_y = column_up[pos_x].no - 1; + + if (pos_y < 0) + { + pos_y = 0; + } + } + break; + + case KEY_UP: + if (pos_y) + { + pos_y--; + } + break; + + case KEY_DOWN: + if (pos_y < column_up[pos_x].no - 1) + { + pos_y++; + } + break; + + case '?': + KlondikeHelp(); + break; + + default: + break; + } + } + + if (show) + { + for(f = 0; f < 7; f++) + { + for(n = 0; n < column_down[f].no; n++) + { + DrawCard(2 + n, 1 + f * 5, FALSE, column_down[f].card[n]); + } + + for(n = 0; n < column_up[f].no; n++) + { + DrawCard(2 + column_down[f].no + n, 1 + f * 5, + FALSE, column_up[f].card[n]); + } + } + + Centre(LINES - 1, "Press any key"); + refresh(); + getch(); + } + + if (won) + { + WinScreen(); + } + + FreePile(&pile); + FreePile(&turned); + FreePile(&hearts); + FreePile(&diamonds); + FreePile(&clubs); + FreePile(&spades); + for(f = 0; f < 7; f++) + { + FreePile(&column_down[f]); + FreePile(&column_up[f]); + } +} + + +/* +vim: ai sw=4 ts=8 expandtab +*/ -- cgit v1.2.3