Created
June 26, 2017 23:12
-
-
Save LukeMS/41214c1f0e6e750ce95373dcdd1f6bcd to your computer and use it in GitHub Desktop.
blackjack.c - learning exercise
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* A simple blackjack game in C */ | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#define NUM_SUITS 4 | |
#define NUM_RANKS 13 | |
#define HEARTS 3 | |
#define DIAMONDS 4 | |
#define CLUBS 5 | |
#define SPADE 6 | |
#define H 196 | |
#define V 179 | |
#define TL 218 | |
#define BL 192 | |
#define TR 191 | |
#define BR 217 | |
#define CARD_ROWS 7 | |
struct Card { | |
char suit; | |
char rank; | |
char value; | |
bool ace; | |
}; | |
void play_sound(int n) { | |
for(;n > 0; n--) { | |
printf("\a"); | |
} | |
} | |
const char rank_code[] = {'2', '3', '4', '5', '6', '7', '8', | |
'9', 'T', 'J', 'Q', 'K', 'A'}; | |
const char suit_code[] = {CLUBS, DIAMONDS, HEARTS, SPADE}; | |
bool better_then(int a, int b) { | |
return a <= 21 && (21 - a) < (21 - b); | |
} | |
int get_dealer_action(int dealer_score) { | |
// The dealer must stand on 17 or higher and hit below 17. | |
if (dealer_score >= 17) { | |
return 2; | |
} | |
return 1; | |
} | |
void print_cards(struct Card *cards, size_t num_cards, bool dealer) { | |
for (int line = 0; line < CARD_ROWS; ++line) { | |
for (unsigned i = 0; i < num_cards; ++i) { | |
if (i > 0 && dealer && line > 0 && line < 6) { | |
printf("%c#####%c", V, V); | |
continue; | |
} | |
switch (line) { | |
case 0: | |
printf("%c%c%c%c%c%c%c", TL, H, H, H, H, H, TR); | |
break; | |
case 1: | |
printf("%c%c %c", V, cards[i].suit, V); | |
break; | |
case 3: | |
if (cards[i].rank == 'T') { | |
printf("%c 10 %c", V, V); | |
} else { | |
printf("%c %c %c", V, cards[i].rank, V); | |
} | |
break; | |
case 5: | |
printf("%c %c%c", V, cards[i].suit, V); | |
break; | |
case 6: | |
printf("%c%c%c%c%c%c%c", BL, H, H, H, H, H, BR); | |
break; | |
default: | |
printf("%c %c", V, V); | |
break; | |
} | |
} | |
printf("\n"); | |
} | |
} | |
void print_game_table(int player_score, int dealer_score, struct Card *player_cards, struct Card *dealer_cards, size_t num_player_cards, size_t num_dealer_cards, bool player_done, bool dealer_done) { | |
printf("\nDealer(%2d): \n", dealer_score); | |
print_cards(dealer_cards, num_dealer_cards, | |
!player_done && !dealer_done); | |
printf("\nYou(%2d):\n", player_score); | |
print_cards(player_cards, num_player_cards, false); | |
} | |
struct Card draw(bool (*in_hand)[NUM_SUITS][NUM_RANKS]) { | |
struct Card card; | |
int rank, suit; | |
for (;;) { | |
suit = rand() % NUM_SUITS; /* picks a random suit */ | |
rank = rand() % NUM_RANKS; /* picks a random rank */ | |
if (!(*in_hand)[suit][rank]) { | |
card.suit = suit_code[suit]; | |
card.rank = rank_code[rank]; | |
if (rank == 12) { | |
card.value = 1; | |
card.ace = 1; | |
} else if (rank < 9) { | |
card.value = rank + 2; | |
card.ace = 0; | |
} else { | |
card.value = 10; | |
card.ace = 0; | |
} | |
(*in_hand)[suit][rank] = true; | |
return card; | |
} | |
} | |
} | |
int get_score(struct Card *cards, size_t num_cards) { | |
int sum = 0, aces = 0; | |
for (unsigned i = 0; i < num_cards; ++i) { | |
sum += cards[i].value; | |
aces += cards[i].ace; | |
} | |
for (; aces > 0; aces--) { | |
if (better_then(sum + 10, sum)) { | |
sum += 10; | |
} | |
} | |
return sum; | |
} | |
int deal(float *cash, float *bet) { | |
bool in_hand[NUM_SUITS][NUM_RANKS] = {{ false }}; // control cards so that they don't repeat | |
size_t num_cards = 21; | |
struct Card dealer_cards[num_cards], player_cards[num_cards]; | |
size_t num_dealer_cards = 0, num_player_cards = 0; | |
bool player_done = false, dealer_done = false; | |
int player_score, dealer_score; | |
float result = 0.0f; | |
srand((unsigned) time(NULL)); | |
printf("\n*** Welcome to ClackJack - a C BlackJack! ***\n"); | |
for (; num_player_cards < 2; ++num_player_cards) { | |
player_cards[num_player_cards] = draw(&in_hand); | |
} | |
for (; num_dealer_cards < 2; ++num_dealer_cards) { | |
dealer_cards[num_dealer_cards] = draw(&in_hand); | |
} | |
int player_action, dealer_action; | |
for (;;) { | |
player_score = get_score(player_cards, num_player_cards); | |
dealer_score = get_score(dealer_cards, num_dealer_cards); | |
print_game_table(player_score, dealer_score, | |
player_cards, dealer_cards, | |
num_player_cards, num_dealer_cards, | |
player_done, dealer_done); | |
if ((player_score == 21) && (dealer_score == 21)) { | |
printf("Tied hand!"); | |
break; | |
} | |
else if (player_score == 21) { | |
if (num_player_cards == 2) { | |
result = (*bet) * 1.5; | |
printf("Blackjack!"); | |
play_sound(4); | |
} else { | |
result = (*bet); | |
printf("You win!"); | |
play_sound(2); | |
} | |
break; | |
} else if (dealer_score == 21) { | |
result = -(*bet); | |
printf("Dealer wins!"); | |
play_sound(1); | |
break; | |
} else if (player_done && dealer_done) { | |
if (better_then(player_score, dealer_score)) { | |
result = (*bet); | |
printf("You win!"); | |
play_sound(2); | |
break; | |
} else { | |
result = -(*bet); | |
printf("Dealer wins!"); | |
play_sound(1); | |
break; | |
} | |
} | |
else if (player_score > 21) { | |
result = -(*bet); | |
printf("You busted!"); | |
play_sound(1); | |
break; | |
} else if (dealer_score > 21) { | |
result = (*bet); | |
printf("Dealer busted!"); | |
play_sound(2); | |
break; | |
} | |
printf("\n(1 - Hit, 2 - Stand)\n"); | |
printf("What would you like to do? "); | |
if (!player_done) { | |
scanf("%1d", &player_action); | |
switch (player_action) { | |
case 1: | |
if (num_player_cards < num_cards) { | |
player_cards[num_player_cards] = draw(&in_hand); | |
++num_player_cards; | |
player_score = get_score(player_cards, num_player_cards); | |
if (player_score >= 21) { | |
player_done = true; | |
} | |
} | |
break; | |
case 2: | |
player_done = true; | |
break; | |
} | |
} | |
// Once the dealer has dealt additional cards to all the players, the dealer draws cards for his/her hand. | |
if (player_done && !dealer_done) { | |
dealer_action = get_dealer_action(dealer_score); | |
switch (dealer_action) { | |
case 1: | |
dealer_cards[num_dealer_cards] = draw(&in_hand); | |
++num_dealer_cards; | |
break; | |
case 2: | |
dealer_done = true; | |
break; | |
} | |
dealer_score = get_score(dealer_cards, num_dealer_cards); | |
if (dealer_score >= 21) { | |
dealer_done = true; | |
} | |
} | |
} | |
if (result > 0) { | |
printf(" You've earned $%.2f\n", result); | |
} else if (result < 0) { | |
printf(" You've lost $%.2f\n", result); | |
} | |
return result; | |
} | |
void change_bet(float *cash, float *bet) { | |
float new_bet; | |
for (;;) { | |
printf("\nEnter a valid bet: "); | |
scanf("%f", &new_bet); | |
if (new_bet <= (*cash)) { | |
(*bet) = new_bet; | |
return; | |
} | |
} | |
} | |
int main(void) { | |
float cash = 1000.0f, bet = 250.0f; | |
float *cash_p = &cash; | |
float *bet_p = &bet; | |
int player_action; | |
do { | |
if (cash < bet) { | |
bet = cash; | |
} | |
if (cash <= 0.01f) { | |
printf("You are broke! Sounds like a good time to stop..."); | |
break; | |
} | |
printf("\n(Options: 1 - Deal (bet %.2f); 2 - Change bet; 0 - Quit)\n", | |
bet); | |
printf("What would you like to do? (cash %.2f)", cash); | |
scanf("%1d", &player_action); | |
switch (player_action) { | |
case 1: | |
cash += deal(cash_p, bet_p); | |
break; | |
case 2: | |
change_bet(cash_p, bet_p); | |
break; | |
default: | |
return 0; | |
break; | |
} | |
} while (1); | |
printf("\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Screenshot: