Normally I code in Java but have recently been trying to teach myself C for a university course I will be taking next semester. (I'm about to enter my third year). I wouldn't consider myself the best programmer, or even a good one.
Now, I was just wondering if anyone would be able to take a quick look through my attempt at making a terminal based Blackjack game in C and tell me if there are any glaring holes in how I've made it. I'm not used to writing C or larger procedural code projects for that matter, so I'm sure I've done a lot of silly things. I've included the main.c file below, but here is the GitHub link for the rest of it.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "data.h"
#include "deck.h"
#define MAX_CARDS 25
Hand deal_player_hand(Deck deck);
Card* get_random_card(Deck deck);
Hand deal_dealer_hand(Deck deck);
void print_card(Card* card);
void print_hand(Hand player_hand);
char* suite_to_string(int suite);
void hit(Hand player_hand, Deck deck);
char get_user_response();
bool check_valid(char input);
Card* deal_card(Hand player_hand, Deck deck);
bool check_bust(Hand hand);
void dealer_hit(Hand dealer_hand, Deck deck);
int sum_hand(Hand hand);
void check_winner(Hand player_hand, Hand dealer_hand);
int main() {
Deck deck = create_deck();
Hand player_hand = deal_player_hand(deck);
Hand dealer_hand = deal_dealer_hand(deck);
printf("\nPlayer Hand:\n");
print_hand(player_hand);
printf("\nDealer Hand:\n");
print_hand(dealer_hand);
hit(player_hand, deck);
dealer_hit(dealer_hand, deck);
check_winner(player_hand, dealer_hand);
return 0;
}
void dealer_hit(Hand dealer_hand, Deck deck) {
int sum;
do {
printf("\nThe dealer deals themself a card\n");
printf("Dealer Hand:\n");
deal_card(dealer_hand, deck);
print_hand(dealer_hand);
sum = sum_hand(dealer_hand);
} while(sum < 16);
if (sum <= 21) {
printf("\nThe dealer's hand is above 16, they must sit.");
} else if (sum > 21) {
printf("\nThe dealer has gone bust!\n");
}
}
Hand deal_player_hand(Deck deck) {
Hand player_hand = malloc(sizeof(Card*) * MAX_CARDS); // not possible to draw more than 25 cards
for (int i = 0; i < MAX_CARDS; i++) {
player_hand[i] = NULL;
}
player_hand[0] = get_random_card(deck);
player_hand[1] = get_random_card(deck);
return player_hand;
}
Hand deal_dealer_hand(Deck deck) {
Hand dealer_hand = malloc(sizeof(Card*) * MAX_CARDS); // not possible to draw more than 25 cards
for (int i = 0; i < MAX_CARDS; i++) {
dealer_hand[i] = NULL;
}
dealer_hand[0] = get_random_card(deck);
return dealer_hand;
}
Card* get_random_card(Deck deck) {
srand(time(NULL));
int random_index;
do {
random_index = rand() % DECK_SIZE;
} while (deck[random_index]->dealt == true);
Card* random_card = deck[random_index];
random_card->dealt = true;
return random_card;
}
// deals a random card to the next available slot in player or dealer's hand
Card* deal_card(Hand hand, Deck deck) {
Card* card = NULL;
for (int i = 0; i < MAX_CARDS; i++) {
if (hand[i] == NULL) {
card = get_random_card(deck);
hand[i] = card;
break;
}
}
return card;
}
void hit(Hand player_hand, Deck deck) {
bool stop_hitting = false;
while (!stop_hitting && !check_bust(player_hand)) {
printf("\nHit? (y/n)\n");
char input = get_user_response();
if (input == 'n') {
stop_hitting = true;
} else {
Card* card = deal_card(player_hand, deck);
print_card(card);
}
}
if (check_bust(player_hand)) {
printf("You've gone bust\n");
printf("Game Over\n");
exit(0);
}
printf("Player Hand:\n");
print_hand(player_hand);
}
void check_winner(Hand player_hand, Hand dealer_hand) {
int player_sum = sum_hand(player_hand);
int dealer_sum = sum_hand(dealer_hand);
printf("\nSum of Player's hand: %d\n", player_sum);
printf("Sum of Dealer's hand: %d\n", dealer_sum);
if (player_sum == dealer_sum) {
printf("It's a draw!\n");
} else if (player_sum < dealer_sum) {
printf("The house wins!\n");
} else if (player_sum > dealer_sum) {
printf("You win!\n");
}
}
//###########################
// GRAPHICS FUNCTIONS
//###########################
void print_card(Card* card) {
char* suite = suite_to_string(card->suite);
printf("%s of %s\n", card->name, suite);
}
void print_hand(Hand player_hand) {
int value = 0;
for (int i = 0; i < MAX_CARDS; i++) {
Card* card = player_hand[i];
if (card == NULL) {
break;
}
value += card->value;
print_card(card);
}
printf("Sum: %d\n", value);
}
//###########################
// UTILITY FUNCTIONS
//###########################
char* suite_to_string(int suite) {
char *suite_name = malloc(sizeof(char) * 10);
switch (suite) {
case DIAMONDS:
strcpy(suite_name, "Diamonds");
break;
case CLUBS:
strcpy(suite_name, "Clubs");
break;
case SPADES:
strcpy(suite_name, "Spades");
break;
case HEARTS:
strcpy(suite_name, "Hearts");
break;
default:
strcpy(suite_name, "ERROR");
}
return suite_name;
}
bool check_valid(char input) {
bool valid = false;
if (input == 'y' || input == 'n') {
valid = true;
}
return valid;
}
// determines if this hand has gone over 21.
bool check_bust(Hand hand) {
bool bust = false;
int sum = sum_hand(hand);
if (sum > 21) {
bust = true;
}
return bust;
}
int sum_hand(Hand hand) {
int sum = 0;
for (int i = 0; i < MAX_CARDS; i++) {
if (hand[i] != NULL) {
sum += hand[i]->value;
}
}
return sum;
}
//###########################
// File IO Functions
//###########################
// gets first char entered by user on command line
char get_user_response() {
char input;
scanf(" %c", &input);
while(!check_valid(input)) {
printf("Invalid input. Please enter y/n\n");
scanf(" %c", &input);
}
return input;
}
Thank you in advance for any suggestions you may have!
Card
,Deck
andHand
, please? The code won't compile without them. \$\endgroup\$