C, card game WAR - c

I am trying to create a War card game using C. Instead of making 2 decks for the "discarded" cards to be added to a players hand at a later time, I am instead just trying to add the dealers card[i] - which was previously compared with players card[i] to ensure that the player won the hand - to the players hand directly. index is used to make sure there are no empty elements playerhand ever points to by appending another card on to the end of the “hand,” which initially has 26 cards (half the deck). the deck is initially split in 2, the first 26 cards deck[0-25] going to the player's hand, and the last 26 deck[26-51] going to the dealers hand.
here is my code in question:
//adds new card to deck at given index
void addToPlayerHand(int i) {
int index=0;
playerHand[index+26] = deck[i+26];
index++;
}
here is my full game code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//Type Stucture for Card
typedef struct cards {
char suit;
int face;
struct cards *listp; // didn't use in this program
} card;
//Functions
//
int welcome();
//int checkWinWar();
int playGame();
int getComparison(card *firstCard,card *secndCard,int index);
void printingGame(int a,int b, int i);
void addToPlayerHand(int i);
void addToDealerHand(int i);
int addToDeck(card myCards, int index);
void hitPlayer(card theCard);
void hitDealer(card theCard);
void initilizeDeck();
int shuffleDeck();
int printFun(); // not used for game play
void freePlayers();
//Card Dynamics
//
card *playerHand; // contains contents of players cards
card *dealerHand; // contains contents of dealers cards
//Deck of 52 Cards with discard decks
card deck[52];
card playerDeck[52];
card dealerDeck[52];
int numPlayer = 0;
int numAllPlayer = 0;
int numDealer = 0; // needed for temp
int numAllDealer = 0;
//Main
int main(void) {
printf("Hello..Welcome to WAR\n");
//Game loop
while (welcome() == 1) { // welcome returns whether the player wants to play (1) or not (0)
// put first card face up
// display how many cards
// indicate (if/if no) war has occurred
// complete the war
// add cards to player discard pile
// check player for card count
// if end game conition met, end hame
if(playGame() == 1) { // playGame returns 1 if the function went through correctly
if(checkWinWar()==1){
}
else{
}
} else {
printf("Bust! Try Again\n\n");
freePlayers(); // refreshes the dynamics of the hands
}
}
//initilizeDeck();
//shuffleDeck();
//printFun();
return 0;
}
//To allow the player to begin the game; 1 = True 0 = False
int welcome() {
printf("Play a new round of WAR? (enter/return for yes):\t");
if(getchar()=='\n'){
return 1;
}
else
return 0;
}
// refreshes the game and players
void freePlayers () {
numDealer = 0;
numPlayer = 0;
numAllPlayer = 0;
numAllDealer = 0;
free(playerHand);
free(dealerHand);
playerHand = NULL; // needed so playerHand doesn't point to anything
dealerHand = NULL;
return;
}
// Playing of the game
int playGame() {
initilizeDeck(); // initialize Deck returns the new deck of cards
shuffleDeck(); // shuffleDeck returns the shuffled deck of cards
int gameTrue = 1; // gameTrue checks the state of the game
int war = 0;
int PlayerCardsRemaining=0;
int DealerCardsRemaining=0;
int temp,i,j=0;
while (gameTrue == 1) {
// splitting the deck
for (j=0;j<26;j++){
hitPlayer(deck[j]); // adding cards to playerHand
PlayerCardsRemaining+=1; //adding to player deck count.
}
for (j=26;j<52;j++){
hitDealer(deck[j]);
DealerCardsRemaining+=1;} // adding to dealer deck count.
i=0;
while(PlayerCardsRemaining>0 && DealerCardsRemaining>0 && i<26) {
printingGame(DealerCardsRemaining,PlayerCardsRemaining, i);
if (getComparison(playerHand, dealerHand, i)==0){
addToDealerHand(i);
DealerCardsRemaining++;
return 1;
}
else if(getComparison(playerHand,dealerHand,i)==1){
addToPlayerHand(i);
PlayerCardsRemaining++;
return 1;
}
else if(getComparison(playerHand, dealerHand, i)==2){
printf("There is an impending WAR\n");
printf("press enter to engage in the WAR");
war=1;
if(war==1 && DealerCardsRemaining>=4 && PlayerCardsRemaining>=4){
temp=getComparison(playerHand, dealerHand, i+4);
while(war==1){
if(temp==0){
for(i=i;i<i+4;i++){
addToDealerHand(i);
}
war=0;
PlayerCardsRemaining-=4;
DealerCardsRemaining+=4;
}
else if(temp==1){
for(i=i;i<i+4;i++){
addToPlayerHand(i);
}
war=0;
DealerCardsRemaining-=4;
PlayerCardsRemaining+=4;
}
else
war=1;
}
return 1;
}
if (DealerCardsRemaining<<4){
for(i=i;i<i+4;i++){
addToPlayerHand(i);
}
}
else if (PlayerCardsRemaining<<4){
for(i=i;i<i+4;i++){
addToDealerHand(i);
}
}
}
i++; // increment i
}
}
return 0;
}
void printingGame(int DealerCardsRemaining, int PlayerCardsRemaining, int i)
{
// Gameplay Prompts
//Prints interface that comes up after player(s) choose to play
printf("*********\t\t*********\n");
printf("*\t \t*\t\t*\t \t*\n");
// Cases for cards that are face cards
if(dealerHand[i].face==11){ // if dealer card is a jack
printf("*\tJ\t*\t\t");
if (playerHand[i].face<11){ // if player card isnt a face card
printf("*\t%d\t*\n",playerHand[i].face);
}
else if(playerHand[i].face==11){ // if player card is a face card
printf("*\tJ\t*\n");
}
else if(playerHand[i].face==12){
printf("*\tQ\t*\n");
}
else if(playerHand[i].face==13){
printf("*\tK\t*\n");
}
else if(playerHand[i].face==14){
printf("*\tA\t*\n");
}
}
else if(dealerHand[i].face==12){ // if dealer card is a queen
printf("*\tQ\t*\t\t");
if (playerHand[i].face<11){ // if player card isnt a face card
printf("*\t%d\t*\n",playerHand[0].face);
}
else if(playerHand[i].face==11){ // if player card is a face card
printf("*\tJ\t*\n");
}
else if(playerHand[i].face==12){
printf("*\tQ\t*\n");
}
else if(playerHand[i].face==13){
printf("*\tK\t*\n");
}
else if(playerHand[i].face==14){
printf("*\tA\t*\n");
}
}
else if(dealerHand[i].face==13){ // if dealer card is a king
printf("*\tK\t*\t\t");
if (playerHand[i].face<11){ // if player card isnt a face card
printf("*\t%d\t*\n",playerHand[i].face);
}
else if(playerHand[i].face==11){ // if player card is a face card
printf("*\tJ\t*\n");
}
else if(playerHand[i].face==12){
printf("*\tQ\t*\n");
}
else if(playerHand[i].face==13){
printf("*\tK\t*\n");
}
else if(playerHand[i].face==14){
printf("*\tA\t*\n");
}
}
else if(dealerHand[i].face==14){ // if dealer card is an ace
printf("*\tA\t*\t\t");
if (playerHand[i].face<11){ // if player card isnt a face card
printf("*\t%d\t*\n",playerHand[i].face);
}
else if(playerHand[i].face==11){ // if player card is a face card
printf("*\tJ\t*\n");
}
else if(playerHand[i].face==12){
printf("*\tQ\t*\n");
}
else if(playerHand[i].face==13){
printf("*\tK\t*\n");
}
else if(playerHand[i].face==14){
printf("*\tA\t*\n");
}
}
if (dealerHand[i].face<11 && playerHand[i].face<11){ // if both cards arent face cards
printf("*\t%d\t*\t\t*\t%d\t*\n",dealerHand[i].face,playerHand[i].face);
}
printf("*\t \t*\t\t*\t \t*\n");
printf("*********\t\t*********\n");
printf("Dealer: %d cards. ",DealerCardsRemaining); // print how many cards the 'dealer' has
printf("Player: %d cards. ",PlayerCardsRemaining); // print how many cards the player has
}
int getComparison (card *firstCard, card *secndCard, int i)
{
int a,b;
a=firstCard[i].face;
b=secndCard[i].face;
if (b>a)
return 0;
else if (a>b)
return 1;
else
return 2;
}
// gives player another card
void hitPlayer (card theCard) {
if(numPlayer == 0) { // if hitPlayer is giving playerHand its first card (for new deck or initial deck)
if (numAllPlayer == 0) // if its the first hand
numAllPlayer = 1; // there is only one card in need of space
else // if its not the first hand
numAllPlayer++; // you need space for all existing cards plus the one just added
void *_tmp = realloc(playerHand, (numAllPlayer * sizeof(card))); // realloc is used since playerHand never has a constant size
if (!_tmp)
{
fprintf(stderr, "ERROR: Couldn't realloc memory!\n"); // stderr prints
}
playerHand = (card*)_tmp; // playerHand is card type pointer which points to void pointer tmp which is reallocating memory
}
playerHand[numPlayer] = theCard;
numPlayer++;
}
// gives dealer another card
void hitDealer (card theCard) {
if(numDealer == 0) {
if (numAllDealer == 0)
numAllDealer = 1;
else
numAllDealer++;
void *_tmp = realloc(dealerHand, (numAllDealer * sizeof(card)));
if (!_tmp)
{
fprintf(stderr, "ERROR: Couldn't realloc memory!\n");
}
dealerHand = (card*)_tmp;
}
dealerHand[numDealer] = theCard;
numDealer++;
}
// creates a new deck of cards
void initilizeDeck() {
//Loop Indexes like: count, i.... etc
int i, p;
int count = 0;
card temp;
for (i = 1; i < 5; i++) {
for (p = 2; p <= 14; p++) {
//Clubs
if (i == 1) {
temp.suit = 'C';
temp.face = p;
}
//Diamonds
if (i == 2) {
temp.suit = 'D';
temp.face = p;
}
//Hearts
if (i == 3) {
temp.suit = 'H';
temp.face = p;
}
//Spades
if (i == 4) {
temp.suit = 'S';
temp.face = p;
}
addToDeck(temp, count);
count++;
}
}
}
//adds new card to deck at given index
int addToDeck(card myCards, int index) {
deck[index] = myCards;
return 1;
}
//adds new card to deck at given index
void addToPlayerHand(int i) {
int index=0;
playerHand[index+26] = deck[i+26];
index++;
}
//adds new card to deck at given index
void addToDealerHand(int i) {
int index=0;
dealerHand[index+26] = deck[i];
index++;
}
//finds deck and shuffles cards 100 times from swaping a random value from 1-52
int shuffleDeck() {
card temp; // for an individual card
int i,p;
srand(time(NULL));
for (i = 0; i < 100; i++) {
for (p = 0; p < 52; p++) {
int r = rand()%52;
temp = deck[p]; // swaps to randomly pick another card
deck[p] = deck[r];
deck[r] = temp;
}
}
return 0;
}
it keeps telling me i have a bad access code, code=2.
any help would be awesome.

I'll dispense with the "I'd never code this that way" dialogue long enough to suggest that this loop ideology:
for(i=i;i<i+4;i++)
will look well past the limits of your card arrays and into the land of undefined behavior. Think about it a minute. Then ask yourself this question: At what point will i no longer be less than i+4 ? Answer: when you reach the point when i+4 overflows to become negative (assuming the optimizer doesn't throw out the condition entirely and just assume it is always true; thanks Jeremy).
I.e. INT_MAX-3. On a 32-bit system that is only about 2147483562 slots past the end of your array.
This error is repeated 3 more times in the playGame() function.

Related

removing user chosen nodes from a linked list, replacing them with nodes from another list in c

I'm trying to write a poker program. Pretty much everything works right now, the one issue is where the program asks the user which cards they want to keep, and which they want to discard. If it worked as intended, the user would enter which cards they want to keep. The cards that weren't selected would then be removed, and replaced with cards from the deck. The player's hand and the deck are two separate linked lists.
This part of the program behaves kind of strangely. Sometimes it works fine. Other times, it discards cards that were meant to be kept, or keeps card that were meant to be discarded. It sometimes also changes the suit of some of the cards (or maybe it's duplicating certain cards, I'm not sure).
This is the function that creates the deck:
card *
createCard(int n)
{
int i = 0;
card *head = (card *) malloc(sizeof(card));
card *tmp = NULL;
card *p = NULL;
p = head;
for (i = 0; i < n - 1; i++) {
tmp = (card *) malloc(sizeof(card));
p->next = tmp;
p = p->next;
p->next = NULL;
}
tmp = head;
for (i = 1; i <= 13; i++) {
for (int j = 3; j <= 6; j++) {
tmp->face = i;
tmp->suit = j;
tmp = tmp->next;
}
}
return (head);
}
This is the function that creates the player's hand(by creating a new linked list from the first five nodes of the deck list):
void
createHand(card ** deck, card ** hand)
{
card *tmp = NULL;
card *card = *deck;
int i;
//while (card != NULL)
for (i = 0; i < 5; i++) {
(*deck) = (*deck)->next;
tmp = card->next;
card->next = *hand;
*hand = card;
card = tmp;
}
(*hand)->next->next->next->next->next = NULL;
return;
}
This is the section of code that's not working(note: playerHand is the player's hand, first is the deck):
i = 1;
// this array keeps track of which cards the user wants to keep
int a[] = { 0, 0, 0, 0, 0 };
while (i <= 5) {
printf("Pick cards (between 1-5) to hold (-1 to stop): ");
scanf("%d", &keep);
// breaks from loop if the user enters -1
if (keep == -1)
break;
if (keep == 0 || keep > 5 || keep <= -2) {
printf("Invalid index. Pick cards (between 1-5) to hold (-1 to stop): ");
scanf("%d", &keep);
if (keep == -1)
break;
}
if (keep == -1) {
break;
}
if (keep != -1) {
// when player wants to keep a card, the corresponding index of that
// card is set to one in the array
a[keep - 1] = 1;
}
i++;
}
card *tmp;
tmp = first;
card *tmp2;
tmp2 = playerHand;
for (i = 0; i < 5; i++) {
// if the corresponding index in the array is 0, that card is replaced
if (a[i] == 0) {
tmp2->face = tmp->face;
tmp2->suit = tmp->suit;
}
first = first->next;
free(tmp);
tmp = first;
tmp2 = tmp2->next;
}
The cards don't change when this section of code is removed, so the error must be here somewhere, I'm just not sure where.
This is what the output would look like while the player is choosing which cards to keep. In this case, the player is choosing to keep the first and third cards and discarding the other three:
Pick cards (between 1-5) to hold (-1 to stop): 1
Pick cards (between 1-5) to hold (-1 to stop): 3
Pick cards (between 1-5) to hold (-1 to stop): -1
Perhaps the code should look like this? How does the player choose the replacement cards?
Can you show what the code for saving cards for replacement looks like?
card *tmp;
tmp = first;
card *tmp2;
tmp2 = playerHand;
for (i = 0; i < 5; i++) {
if (a[i] == 0) {//if the corresponding index in the array is 0, that card is replaced
tmp2->face = tmp->face;
tmp2->suit = tmp->suit;
first = first->next;
free(tmp);
tmp = first;
}
tmp2 = tmp2->next;
}
After the user chooses the cards to replace, we take the first n cards from the deck.
The mistake in your code is that the top five cards of the deck are always discarded. If the card in the hand was marked for discarding, then not the next card from the deck was taken, but a card with the same index.
card *tmp;
tmp = first;
card *tmp2;
tmp2 = playerHand;
for (i = 0; i < 5; i++) {
// if the corresponding index in the array is 0,
// the card will be replaced by a card with the same index from the deck
if (a[i] == 0) {
tmp2->face = tmp->face;
tmp2->suit = tmp->suit;
}
first = first->next; //changes the top of the deck to the next
free(tmp); //always removes a card from the deck
//so the first 5 cards will be removed
tmp = first; //all these three lines must be moved to the condition if
tmp2 = tmp2->next;
}
and in the while loop, you need to change the code, because if the user enters the wrong index twice in a row, the program will crash
if (keep == 0 || keep > 5 || keep <= -2) {
printf("Invalid index. ");
continue;
}

Suggestions/improvements on my simple Blackjack program

I am trying to get a head start on my class next semester so I made this basic version of Blackjack to start understanding the basics of C and I would love any thoughts you have that could help me gain a better understanding of C and its normal coding practices.
A lot of the things in C are new to me as I am coming from a background in JAVA so if I made a mistake in function declaration, in my use of pointers, or if I was thinking about how to approach the problem incorrectly and should have done things a completely different way please let me know.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
const int handSize = 2;
int randCard(int *isAce);
int sumCards(int cards[], int *hasAce[2]);
int main() {
srand(time(NULL));
int playGame = 0;
int dealerIsAce[handSize];
int *dealerAcePointers[handSize];
int playerIsAce[handSize];
int *playerAcePointers[handSize];
for (int i = 0; i < handSize; i++) {
dealerIsAce[i] = 0;
playerIsAce[i] = 0;
dealerAcePointers[i] = &dealerIsAce[0];
playerAcePointers[i] = &playerIsAce[0];
}
int dealerCards[] = {randCard(dealerAcePointers[0]), randCard(dealerAcePointers[1])};
int playerCards[] = {randCard(playerAcePointers[0]), randCard(playerAcePointers[1])};
int dealerSum;
int playerSum;
do {
printf("The dealer:\n? + %d\n\n", dealerCards[1]);
dealerSum = sumCards(dealerCards, dealerAcePointers);
if (dealerSum > 17) {
dealerCards[0] = dealerSum;
dealerCards[1] = randCard(dealerAcePointers[1]);
}
playerSum = sumCards(playerCards, playerAcePointers);
printf("You:\n%d + %d = %d", playerCards[0], playerCards[1], playerSum);
if (playerSum > 21) {
printf(" BUSTED");
playGame = 1;
} else {
printf("\nWould you like to \"hit\" or \"stand\"?\n");
}
if (playGame == 0) {
char stream[10];
if (strcmp(gets(stream), "hit") == 0) {
playerCards[0] = playerSum;
playerCards[1] = randCard(playerAcePointers[1]);
} else {
playGame = 1;
}
}
} while (playGame == 0);
if (playerSum > 21) {
if (dealerSum > 21) {
printf("\nTie!");
} else {
printf("\nDealer Wins!");
}
} else {
if (playerSum > dealerSum) {
printf("\nPlayer Wins!");
} else if (playerSum == dealerSum) {
printf("\nTie!");
} else if (playerSum < dealerSum) {
printf("\nDealer Wins!");
}
}
return 0;
}
int randCard(int *isAce) {
int card = rand() % 13 + 2;
if (card > 11) {
card = 10;
} else if (card == 11) {
*isAce = 1;
}
return card;
}
int sumCards(int cards[], int *hasAce[2]) {
int sum = cards[0] + cards[1];
if (sum > 21 && *hasAce[0] == 1) {
sum -= 10;
*hasAce[0] = *hasAce[1];
if (*hasAce[1] == 1) {
*hasAce = 0;
}
}
return sum;
}
As mentioned by a commenter, this could be better asked elsewhere, however I'm going to offer some opinions anyway. These are all opinions, and everyone will probably disagree with something I've said.
Incidentally, I'm entirely ignoring the rules of BlackJack and assuming that all your logic is correct.
First and foremost, there aren't any comments in the code. You mention this being for a class, therefore commenting is even more important as some poor person has to decipher a load of these to work out what they do. (Commenting code is important anyway incidentally, I always use the "Will I work out what this does in a months time" approach)
Having that much stuff in main() is unusual. I would personally break it out into a different function. You could then also consider putting it in a separate file, with a header file for the function declarations.
handSize is being used as a constant, you could probably make this a preprocessor macro instead: #define HAND_SIZE 2
The do-while loop could be replaced with a while(true) loop, then using the 'break' keyword to escape when you're done (Where you are currently setting playGame = 1. This also has the advantage of not having the if(playGame == 0) conditional. Also, in C, a boolean variable is 1 for true and 0 for false, so it would be more normal to have int playGame = 1; and then do { } while(playGame) and playGame = 0; when you're done with the loop. This case is a special in that you actually want to break out, rather than run to the end of the loop.
gets() was removed in C11 for security reasons (Implicit declaration of 'gets')
On a more whole-program points. These are even more subjective, and are mostly just how I would have solved the problem:
I personally would make dealerCards and playerCards large enough to hold the maximum possible number of cards (which I think is 5 in blackjack?) and initialise them to 0. Currently you are assigning the sum of the current cards to the first element of the dealerCards array, meaning that the values are not actual cards.
Rather than use separate arrays to track whether or not cards are aces, I would have made an enum for {EMPTY_SLOT, ACE, TWO, ..., JACK, QUEEN, KING} and then stored that in my Cards arrays. randCard can then just return a member of the enum, and take no arguments, and sumCards just iterates across the array and sums it. This also means that you can display the user's actual hand to them, rather than just the total.
For reference purposes, I've modified your code to how I would do it. The logic may not be perfect (or the exact same version of blackjack) but this is the sort of thing I would submit for a "program blackjack in C" homework. N.B. This could also do with a few more comments, particularly a block one at the top explaining what the general structure is.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define HAND_SIZE 5
typedef enum
{
// Technically I didn't need to set the values, as they are the defaults but
// it's good to be explicit when you're using the order for something.
EMPTY = 0,
ACE = 1,
TWO = 2,
THREE,
FOUR,
FIVE,
SIX,
SEVEN,
EIGHT,
NINE,
TEN,
JACK,
QUEEN,
KING
} card_t; // Types you typedef generally end _t as a convention.
// These should be in a separate header, but I'm keeping this in 1 file for StackOverflow
card_t randCard();
int sumCards(card_t cards[]);
void play();
int main()
{
srand(time(NULL));
play();
return 0;
}
card_t randCard()
{
int card = rand() % 13 + 1;
return (card_t)card;
}
int sumCards(card_t cards[])
{
int total = 0;
int num_aces = 0;
for (int i = 0; i < HAND_SIZE; i++) {
switch(cards[i]) {
case ACE:
num_aces++;
total += 11;
break;
case JACK:
case QUEEN:
case KING:
total += 10;
break;
default:
total += (int)cards[i]; // Relying here on the fact that the cards are in the correct order.
break;
}
}
while (num_aces > 0 && total > 10) {
total -= 10;
num_aces--;
}
return total;
}
void play()
{
card_t playerCards[HAND_SIZE];
card_t dealerCards[HAND_SIZE];
card_t dealerKnown[HAND_SIZE]; // Equivalent to dealer cards, but with first 2 elements blank
for (int i = 0; i < HAND_SIZE; i++) {
playerCards[i] = EMPTY;
dealerCards[i] = EMPTY;
dealerKnown[i] = EMPTY;
}
playerCards[0] = randCard();
playerCards[1] = randCard();
dealerCards[0] = randCard();
dealerCards[1] = randCard();
int num_cards = 2;
while(num_cards <= HAND_SIZE) {
printf("The dealer: ? + %d\n\n", sumCards(dealerKnown));
if (sumCards(dealerCards) > 17) {
dealerCards[num_cards] = randCard();
}
int playerSum = sumCards(playerCards);
printf("Your total: %d\n", playerSum);
if (playerSum > 21) {
printf("BUSTED\n");
break;
} else {
printf("Would you like to \"hit\" or \"stand\"?\n");
}
char stream[10];
if (strcmp(fgets(stream, sizeof(stream), stdin), "hit\n") != 0) {
break;
}
playerCards[num_cards] = randCard();
num_cards++;
}
printf("\n"); // Printing the new line separately rather than at the beginning of all the strings below
int playerSum = sumCards(playerCards);
int dealerSum = sumCards(dealerCards);
if (playerSum > 21) {
if (dealerSum > 21) {
printf("Tie!");
} else {
printf("Dealer Wins!");
}
} else {
if (playerSum > dealerSum) {
printf("Player Wins!");
} else if (playerSum == dealerSum) {
printf("Tie!");
} else if (playerSum < dealerSum) {
printf("Dealer Wins!");
}
}
printf("\n");
}

Poker Game Results Between Two Players

I'm at the point where I'm trying to rank my players in the game, and determine the winner. You can read my code below, as I think I've documented the logic pretty well throughout.
What I need to do now is determine which player wins, given that there are two players. I've laid out functions for shuffling, dealing, and determining which type of hand it is.
//
// main.c
// Created by gixx88 on 7/22/15.
// Copyright (c) 2015 gixx88. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define SUITS 4
#define FACES 13
#define CARDS 52
#define HAND 5
#define PLAYERS 2
//prototypes for shuffle and deal
void shuffle( size_t wDeck[][FACES] ); //shuffling modifies wDeck
void deal( size_t wDeck[][FACES], const char *wFace[],
const char *wSuit[] ); //dealing doesn't modify the arrays
void dealHand(size_t wHands[][HAND], size_t wDeck[][FACES]);
//prototypes for determing suit and face
size_t determineSuit(size_t wCard);
size_t determineFace(size_t wCard);
//prototypes for determing poker hand
unsigned int findAPair(size_t wHand[HAND]);
unsigned int findTwoPairs(size_t wHand[HAND]);
unsigned int findThreeOfAKind(size_t wHand[HAND]);
unsigned int findFourOfAKind(size_t wHand[HAND]);
unsigned int findFlush(size_t wHand[HAND]);
unsigned int findFullHouse(size_t wHand[HAND]);
unsigned int findStraightFlush(size_t wHand[HAND]);
unsigned int findStraight (size_t wHand[HAND]);
//prototypes for determing player outcomes
unsigned int determingPlayerHand(size_t wHand[HAND]);
void playerRank( size_t wHands[PLAYERS][HAND]);
int main(void) {
//initialize suit array
const char *suit[SUITS] = {"Hearts", "Diamonds", "Clubs", "Spades" };
//initilize face array
const char *face[ FACES ] = { "Ace", "Deuce", "Three", "Four", "Five", "Six", "Seven",
"Eight", "Nine", "Ten", "Jack", "Queen", "King" };
//initilize deck array
size_t deck[ SUITS ][FACES] = {{0}};
size_t hands[PLAYERS][HAND] = {{0}};
srand(time(NULL)); //random seed generator
shuffle(deck); //shuffle the deck
dealHand(hands, deck);
playerRank(hands);
} //end main
//determine suit
size_t determineSuit(size_t wCard){
return wCard / SUITS;
} // end determine suit
//determine face
size_t determineFace(size_t wCard){
return wCard % FACES;
}//end determine face
//if four of a kind
//shuffle cards in deck
void shuffle( size_t wDeck[][FACES] ){
size_t row; //row number
size_t column; //column number
size_t card; //counter
for (card = 0; card <= CARDS; ++card){
//choose a random location until unoccupied slot found
do {
row = rand() % SUITS;
column = rand() % FACES;
} //end do
while (wDeck[row][column] != 0); //end do while
//place card number in chosen slot of deck
wDeck[row][column] = card;
}// end for
} //end shuffle function
//deal cards in deck
void deal( size_t wDeck[][FACES], const char *wFace[],
const char *wSuit[] ){
size_t card; //card counter
size_t row; //row counter
size_t column; //column counter
//deal each of the cards
for (card = 0; card <= CARDS; ++card){
//loop through rows of wDeck
for (row = 0; row < SUITS; ++row){
//loop through columns in wDeck for current row
for(column = 0; column < FACES; ++column){
//if slot contians current card, display card
if (wDeck[row][column] == card){
printf("%5s of %-8s%c", wFace[column], wSuit[row],
card % 2 == 0 ? '\n' : '\t'); //two column format
} //end if
} //end column for
} //end row for
} //end card for
} //end function deal
void dealHand(size_t wHands[][HAND], size_t wDeck[][FACES]){
size_t cards;
size_t players;
unsigned int current;
unsigned int current_suit;
unsigned int current_face;
for (cards = 0; cards <= HAND; cards ++){
for (players = 0; players < PLAYERS; players++){
current = cards * PLAYERS + players;
current_suit = current / SUITS;
current_face = current % FACES;
wHands[players][cards] = wDeck[current_suit][current_face];
} // end players for
} // end cards for
} // end deal hand
//PRINT THE CARD
void printCard(unsigned int wCard, const char wFaces[FACES], const char wSuit[SUITS]){
//find suit and face
size_t suit;
size_t face;
suit = determineSuit(wCard);
face = determineFace(wCard);
printf("%s or %s", wFaces[face], wSuit[suit]);
} //end print card
//******************************
//BEGIN HAND TYPE DETERMINATION
//******************************
//find A PAIR
unsigned int findAPair(size_t wHand[HAND]){
size_t countOfFaces[FACES] = { 0 };
unsigned int foundAPair = 1;
size_t card;
for (card = 0; card < HAND; card++)
{
size_t face = determineFace(wHand[card]);
countOfFaces[face]++;
if (countOfFaces[face] == 3)
{
return 1;
}
else if (countOfFaces[face] == 2)
{
if (foundAPair)
{
return 1;
}
foundAPair = 0;
}
}
return foundAPair;
} // end find a pair
//find TWO PAIRS
unsigned int findTwoPairs(size_t wHand[HAND]){
size_t countOfFaces[FACES] = { 0 };
unsigned int numberOfPairs = 0;
size_t card;
for (card = 0; card < HAND; card++){
size_t face = determineFace(wHand[card]);
countOfFaces[face]++;
if (countOfFaces[face] == 3)
{
return 1;
}
else if (countOfFaces[face] == 2)
{
numberOfPairs++;
}
}
return numberOfPairs == 2;
} //end find two pairs
//find THREE OF A KIND
unsigned int findThreeOfAKind(size_t wHand[HAND]){
size_t countOfFaces[FACES] = {0};
size_t card;
unsigned int foundThree = 1;
for (card = 0; card < HAND; card++){
size_t face = determineFace(wHand[card]);
countOfFaces[face]++;
if (countOfFaces[face] == 3){
foundThree = 0;
} //end if
else if (countOfFaces[face] == 4){
return 1;
} //end else if
else if (countOfFaces[face] == 2 && foundThree){
return 1;
} //end else if
} //end card for loop
return 1;
} //end find three of a kind
//find FOUR OF A KIND
unsigned int findFourOfAKind(size_t wHand[HAND]){
size_t countOfFaces[FACES] = {0};
size_t card;
for (card = 0; card < HAND; card++){
size_t face = determineFace(wHand[card]);
countOfFaces[face]++;
if (countOfFaces[face] == 4){
return 0;
} //end if
} //end card for loop
return 1;
} //end for of a kind
unsigned int findStraight (size_t wHand[HAND]){
size_t card;
size_t lowFace;
size_t highFace;
size_t firstSuit;
unsigned int foundSecondSuit = 1;
for (card = 0; card < HAND; card++)
{
size_t suit = determineSuit(wHand[card]);
size_t face = determineFace(wHand[card]);
// first card
if (card == 0)
{
lowFace = face;
highFace = face;
firstSuit = suit;
}
// all other cards
// check for two equal faces first
else if (face == lowFace || face == highFace)
{
return 1;
}
// update low and high face, if necessary
else
{
if (suit != firstSuit)
{
foundSecondSuit = 0;
}
// an Ace can only go low if the low face is at most a Five
if (face == 0 && lowFace > HAND - 1)
{
face = 13;
}
if (face < lowFace)
{
lowFace = face;
}
if (face > highFace)
{
highFace = face;
}
if ((highFace - lowFace + 1) != HAND)
{
return 1;
}
}
}
return foundSecondSuit;
}
//find FLUSH
unsigned int findFlush(size_t wHand[HAND]){
size_t card;
size_t firstSuit = 5;
for (card = 0; card < HAND; card++){
size_t suit = determineSuit(wHand[card]);
//determing if all cards are the same suit
if (card == 0){
firstSuit = suit;
} //end if
else if (suit != firstSuit){
return 1;
} //end else if
} //end card for loop
return 0;
} //end find flush
//find FULL HOUSE
unsigned int findFullHouse(size_t wHand[HAND]){
if (findAPair(wHand) && findThreeOfAKind(wHand)){
return 0;
} //end if
return 1;
} //end full house
//find STRAIGHT FLUSH
unsigned int findStraightFlush(size_t wHand[HAND]){
size_t lowFace;
size_t highFace;
size_t card;
size_t firstSuit;
for (card = 0; card < HAND; card++){
size_t suit = determineSuit(wHand[card]);
size_t face = determineFace(wHand[card]);
//determing if all cards are the same suit
if (card == 0){
firstSuit = suit;
lowFace = face;
highFace = face;
} //end if
else if (suit != firstSuit || face == lowFace || face == highFace){
return 1;
} //end else if
//determination for ace being high or low, which depends on hand
else
{
// an Ace can only go low if the low face is at most a Five
if (face == 0 && lowFace > HAND - 1)
{
face = 13;
}
if (face < lowFace)
{
lowFace = face;
}
if (face > highFace)
{
highFace = face;
}
if ((highFace - lowFace + 1) != HAND)
{
return 1;
}
}
}
return 0;
} //end straight flush
//****************************
//DETERMINING PLAYER OUTCOMES
//****************************
//determing PLAYER HAND
unsigned int determingPlayerHand(size_t wHand[HAND]){
if (findStraightFlush(wHand) == 0){
return 8;
} //end if
else if (findFourOfAKind(wHand) == 0){
return 7;
} //end else if
else if (findFullHouse(wHand) == 0){
return 6;
} //end else if
else if (findFlush(wHand) == 0){
return 5;
} //end else if
else if (findStraight(wHand) == 0){
return 4;
} //end else if
else if (findThreeOfAKind(wHand) == 0){
return 3;
} //end else if
else if (findTwoPairs(wHand) == 0){
return 2;
} //end else if
else if (findAPair(wHand) == 0){
return 1;
}
return 0;
} //end determing player hand
//determing PLAYER RANK
void playerRank( size_t wHands[PLAYERS][HAND]){
unsigned int player1 = determingPlayerHand(wHands);
unsigned int player2 = determingPlayerHand(wHands);
if (player1 > player2){
printf("%s", "Player 1 Wins!");
}//end if
else if (player2 > player1){
printf("%s", "Player 2 Wins!");
}
} //end player rank
I'm loathe to post this, but sadly, I've got to finish this by tomorrow and I've already been working on it 12 hours straight. My concern is that I set up my poker hand type function to only take one dimension of the two dimensional array. Is there a way to effectively build a ranking system for players with what I have?
Here are some notes I made to myself elsewhere that may also be useful: determingPlayerHand only takes one subscript of the two dimensional array. I need playerRanking to take both subscripts. How can I make this happen so that my rankings will return properly to each player? The ranking returning values should be fine, I think. I initially had it as just true or false, 1 or 0, but then realized that wasn't specific enough
Please let me know what other information I can provide if I need to make this more clear or relevant.
After M Oehm's comment, I want to update this to reflect some other information that I realized would be useful.
Part of the parameters of the problem I'm solving require certain things to be the way they are. If I had my choice in changing them, I think there are better ways to do this as well. However, the deck being as it is, the shuffling algorithm, and the deal algorithm are built to specification of the problem. As for hands evaluating to what they should, so far they do, and I wrote it based on the idea that ace needs to go high at a certain point, which is part of why it's so complicated. The two dimensional array with [PLAYERS][HAND] is meant to make it so that cards are dealt in alternating order to each player from the top of the deck, as would be done in real life.
You have gotten off to a bad start when chosing how to represent your deck and the hands.
You represent the cards as integers from 0 to 51 in the deck's factory order from Ace of Hearts to King of Clubs. That's fine. You can determine the rank and suit from the card number:
rank = card % 13;
suit = card / 13;
That's not what you do in your determineFace/Suit functions. Next, the deck ist a one-dimensional array of cards:
int deck[52];
You can shuffle this array with one of the well-known shuffling algorithms, e.g. Fisher-Yates. You represent the deck as two-dimensional array, which doesn't make the shuffling any easier. It it also not clear what the two dimensions of the deck are. (Okay, they are suit and rank, but after shuffling, that doesn't make sense any longer.)
In a one-dimensional array, the first player's hand are the first five cards and the second player's hand are cards 5 to 9.
Your algorithms to determine the hands are too complicated and have some copy-and-paste errors. Evaluating poker hands boils down to three criteria:
Flush: Are all cards of a hand of the same suit?
Straight: Are all ranks consecutive? (With the special rule that the ace can be played high or lowas appropriate)
Multiples: Most hands have pairs, triplets or quadruplets of cards or combinations thereof, so you need a "histogram" of ranks, sorted by occurrence.
With that data, you can determine your hands. You also need secondary data to distinguish between two equal hands, e.g. a pair of Kings and a pair of Nines.
I suggest you start afresh, switch on compiler warnings and implement shuffling, dealing and the three hand criteria step by step with verification between the steps. (You can call these steps "Milestones", if you like.)

CS50 Pset3 function "Won"

I am at the last part of the pset, and whenever I check my answer using ./fifteen 3 < ~cs50/pset3/3x3.txt , the program doesn't seem to be comparing my solved puzzle with my win[][] array . End result is that I have made an illegal move.
Could this be a problem that board[i][j]==win[i][j] are comparing addresses instead of the values? All help are appreciated
/**
* fifteen.c
*
* Computer Science 50
* Problem Set 3
*
* Implements the Game of Fifteen (generalized to d x d).
*
* Usage: ./fifteen d
*
* whereby the board's dimensions are to be d x d,
* where d must be in [MIN,MAX]
*
* Note that usleep is obsolete, but it offers more granularity than
* sleep and is simpler to use than nanosleep; `man usleep` for more.
*/
#define _XOPEN_SOURCE 500
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// board's minimal dimension
#define MIN 3
// board's maximal dimension
#define MAX 9
// board, whereby board[i][j] represents row i and column j
int board[MAX][MAX];
// board's dimension
int d;
// prototypes
void clear(void);
void greet(void);
void init(void);
void draw(void);
bool move(int tile);
bool won(void);
void save(void);
int main(int argc, string argv[])
{
// greet player
greet();
// ensure proper usage
if (argc != 2)
{
printf("Usage: ./fifteen d\n");
return 1;
}
// ensure valid dimensions
d = atoi(argv[1]);
if (d < MIN || d > MAX)
{
printf("Board must be between %i x %i and %i x %i, inclusive.\n",
MIN, MIN, MAX, MAX);
return 2;
}
// initialize the board
init();
// accept moves until game is won
while (true)
{
// clear the screen
clear();
// draw the current state of the board
draw();
// saves the current state of the board (for testing)
save();
// check for win
if (won())
{
printf("ftw!\n");
break;
}
// prompt for move
printf("Tile to move: ");
int tile = GetInt();
// move if possible, else report illegality
if (!move(tile))
{
printf("\nIllegal move.\n");
usleep(500000);
}
// sleep for animation's sake
usleep(500000);
}
// that's all folks
return 0;
}
/**
* Clears screen using ANSI escape sequences.
*/
void clear(void)
{
printf("\033[2J");
printf("\033[%d;%dH", 0, 0);
}
/**
* Greets player.
*/
void greet(void)
{
clear();
printf("GAME OF FIFTEEN\n");
usleep(2000000);
}
/**
* Initializes the game's board with tiles numbered 1 through d*d - 1,
* (i.e., fills board with values but does not actually print them),
* whereby board[i][j] represents row i and column j.
*/
void init(void)
{
// TODO
//populates the board with all the numbers and the blank space being 0
for(int i=0; i<d; i++)
{
for(int j=0;j<d;j++)
{
board[i][j]= (d*d)-(i*d)-j-1;
//Swap 2 & 1 if number of tiles are even)
if( (d*d)%2 == 0 )
{
//Assign value for original value of 2 to become 1 (swapping)
board[d-1][d-3] = 1;
//Assign value for original value of 1 to become 2 (swapping)
board[d-1][d-2] = 2;
// printf(" %d ",board[i][j]);
}
}
}
}
/**
* Prints the board in its current state.
*/
void draw(void)
{
// TODO
for(int i=0;i<d;i++)
{
for(int j=0;j<d;j++)
{
if(board[i][j]>=10)
{
printf(" %d", board[i][j]);
}
if(board[i][j]<10 && board[i][j]>0)
{
printf(" %2d", board[i][j]);
}
if(board[i][j]== 0)
{
printf(" _");
}
}
printf(" \n");
}
}
/**
* If tile borders empty space, moves tile and returns true, else
* returns false.
*/
bool move(int tile)
{
// TODO
//Find the tile player entered
for(int i=0;i<d;i++)
{
for(int j=0;j<d;j++)
{
//If tile entered is valid
if(tile==board[i][j])
{
// temp value to store tile player wants to move
//check if empty is right of tile | if valid, swap
if(board[i][j+1]==0 && (j+1<d))
{
board[i][j+1]=tile;
board[i][j]=0;
return true;
}
//check if empty is left of tile | if valid, swap
if(board[i][j-1]==0&& (j-1>=0))
{
board[i][j-1]=tile;
board[i][j]=0;
return true;
}
//check if empty is top of tile | if valid, swap
if(board[i-1][j]==0 && (i-1>=0))
{
board[i-1][j]=tile;
board[i][j]=0;
return true;
}
//check if empty is bottom of tile | if valid, swap
if(board[i+1][j]==0 && (i+1<d))
{
board[i+1][j]=tile;
board[i][j]=0;
return true;
}
else
return false;
}
}
}
return false;
}
/**
* Returns true if game is won (i.e., board is in winning configuration),
* else false.
*/
bool won(void)
{
// TODO
int win[MAX][MAX];
for(int i=0;i<d;i++)
{
for(int j=0; j<d; j++)
{
win[i][j]= (i*d)+(j+1);
if(win[i][j]==d*d)
win[i][j]=0;
if(board[i][j]== win[i][j])
return 0;
}
}
return false;
}
/**
* Saves the current state of the board to disk (for testing).
*/
void save(void)
{
// log
const string log = "log.txt";
// delete existing log, if any, before first save
static bool saved = false;
if (!saved)
{
unlink(log);
saved = true;
}
// open log
FILE* p = fopen(log, "a");
if (p == NULL)
{
return;
}
// log board
fprintf(p, "{");
for (int i = 0; i < d; i++)
{
fprintf(p, "{");
for (int j = 0; j < d; j++)
{
fprintf(p, "%i", board[i][j]);
if (j < d - 1)
{
fprintf(p, ",");
}
}
fprintf(p, "}");
if (i < d - 1)
{
fprintf(p, ",");
}
}
fprintf(p, "}\n");
// close log
fclose(p);
}
Could this be a problem that board[i][j]==win[i][j] are comparing
addresses instead of the values?
No, you just got the comparison and the return value in the winning configuration wrong (1 is true, 0 is false; to not get confused, just use 1 and 0), so change in won()
if(board[i][j]== win[i][j])
to
if (board[i][j] != win[i][j])
and
return false;
to
return 1;
then it works.

C -- Trouble with initializing dynamic list

I'm having trouble with the deal function in a blackjack program I am writing. Can anyone see what is going on? When I try to print in main(), I get a segmentation fault.
Cheers.
MAIN FUNCTION
int main(void)
{
int i, j, k, purse;
card deck[52];
card *head_d, *temp_d, *current_d = NULL, *last_d, *head_p, *temp_p, *current_p = NULL, *last_p;
make(deck); //CREATES THE DECK
shuffle(deck); //SHUFFLES THE DECK
deal(deck, head_d, current_d, head_p, current_p)
for(i = 0; i < DECK_SIZE; i++)
{
printf("%d: %d %c\n", i + 1, deck[i].face, deck[i].suit);
}
temp_p = head_p;
while(temp_p != NULL)
{
printf("%d %c\n", temp_p->face, temp_p->suit);
temp_p = temp_p->listp;
}
return(0);
}
FUNCTION deal()
void deal(card x[DECK_SIZE], card *head_d, card *current_d, card *head_p, card *current_p)
{
int i;
card *temp_p, *temp_d;
for(i = 0; i < 4; i++)
{
if( i % 2 == 0)
{
temp_p = (card *)malloc(sizeof(card));
temp_p->face = x[i].face;
temp_p->suit = x[i].suit;
if (current_p==NULL)
{
head_p=temp_p;
}
else
{
current_p->listp=temp_p;
}
current_p = temp_p;
temp_p->listp = NULL;
}
else
{
temp_d=(card *)malloc(sizeof(card));
temp_d->face = x[i].face;
temp_d->suit = x[i].suit;
if (current_d==NULL)
{
head_d=temp_d;
}
else
{
current_d->listp=temp_d;
}
current_d = temp_d;
temp_d->listp = NULL;
}
}
}
The problem is that the arguments to the deal function is local, meaning when you change their value in the function, the variables used when calling the function will not be changed. You need to pass those arguments by reference:
void deal(card x[DECK_SIZE], card **head_d, card **current_d, card **head_p, card **current_p);
The do e.g.
*head_p=temp_p;
in the function to set the variables.
Call as
deal(deck, &head_d, &current_d, &head_p, &current_p);
You have uninitialized pointer variable head_p in your main function. Yet you are attempting to read data supposedly pointed by head_p. Of course, you will get segfault.

Resources