Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
I finished it and it works for the most part. I had a difficult time using the 'A' as 11 and 1. I found a way of doing it with TONS of extra code and writing things to paper first, planning. I sure to you regular programmers this code will look ugly, but it works and it is my first big program :)

The problem I could not solve yet is the 'do while' loop for the "Press 'h' to hit or 's' to stay". If I just hit the return key with no value first it is in an endless loop that I can't get out of even if I enter a value and hit return again.

One question I have that I am unsure of are the string zero - terminators. My char playerCards[15] terminates when I set it up. But then during the execution of the code I will reset the zero terminator from [15] to [3] as I add cards to the list. Is that wrong to do? Can a line of code look like this and be OK, char playerCards[15] = {'-','-','-','-','\0','-','-','-','-','-','-','-','-','-','\0'};

Anyway here is the game.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>



void pCharToInt(int *pTotal,int *pReduceAceValueToOne, char card);
void dCharToInt(int *dTotal, int *dReduceAceValueToOne, char card);

int main (int argc, const char * argv[]) {
	
	int i,randNumberRoll,nextCard,deck,pTotal,dTotal, pBust,dBust,blackJack;
	int gameCount, pWin,dWin, checkForAce, pAcesFound, pReduceAceValueToOne;
	int dAcesFound, dReduceAceValueToOne, displayHideFirstTime;
	
	char playerResponce;
	char mixDeck[53];
	char cards[53] = {'2','2','2','2',
		'3','3','3','3','4','4','4','4','5','5','5','5','6','6',
		'6','6','7','7','7','7','8','8','8','8','9','9','9','9','T',
		'T','T','T','J','J','J','J','Q','Q','Q','Q','K','K','K','K',
	'A','A','A','A','\0'};
	
	srand(clock());
	nextCard = 0;
	deck = 52;
	nextCard = 0;
	gameCount = 0;
	pWin = 0;
	dWin = 0;
	

//----------------------------------------- Mixes the deck to mixDeck array		
	printf("***** Welcome to BlackJack *****\n");
	sleep(1);
	printf("BEST OUT OF 5 GAMES\n\n");
	
	for(i=0 ; i< deck ; i++) 
	{
		randNumberRoll = rand() % (deck);
		do{
			if (cards[randNumberRoll] == '-')
				randNumberRoll = rand() % (deck);
		}while(cards[randNumberRoll] == '-');
		
		mixDeck[i] = cards[randNumberRoll];
		cards[randNumberRoll] = '-';
		
	}
	mixDeck[53] = '\0';

//------------------------------------------------------Game Starts	
	do{
		gameCount++;
		pTotal = 0;
		dTotal = 0;
		blackJack = 0;
		pBust = 0;
		dBust = 0;
		pReduceAceValueToOne = 0;
		pAcesFound = 0;
		dReduceAceValueToOne = 0;
		dAcesFound = 0;
		displayHideFirstTime = 1;
		char playerCards[15] = {'-','-','-','-','-','-','-','-','-','-','-','-','-','-','\0'};
		char dealerCards[15] = {'-','-','-','-','-','-','-','-','-','-','-','-','-','-','\0'};
		
		printf("///////  GAME %d\n", gameCount);
		sleep(1);
//------------------------------------------------------Deals computer cards	
		dealerCards[0] = mixDeck[nextCard];
		dCharToInt(&dTotal,&dReduceAceValueToOne, mixDeck[nextCard]);
		nextCard++;
		dealerCards[2] = mixDeck[nextCard];
		dCharToInt(&dTotal,&dReduceAceValueToOne, mixDeck[nextCard]);
		nextCard++;
		if(dTotal == 22) //----Checks to see if you got 2 A's
		{
			dTotal = 12;
			pAcesFound++;
		}
		printf("\n");
		printf("----> Dealer Cards %c - *?* \n\n",dealerCards[0]);
		
//-----------------------------------------------------Deals player cards	
		
		playerCards[0] = mixDeck[nextCard];
		pCharToInt(&pTotal,&pReduceAceValueToOne, mixDeck[nextCard]);
		nextCard++;
		
		playerCards[2] = mixDeck[nextCard];
		pCharToInt(&pTotal,&pReduceAceValueToOne, mixDeck[nextCard]);
		nextCard++;
		
		playerCards[3] = '\0';
		printf("-> Player Cards %s total = %d \n",playerCards, pTotal);
		if(pTotal == 21)
		{
			printf(" **!!**> YOU GOT BLACK JACK<**!!**\n\n");
			pWin++;
			blackJack = 1;
		}
		if(pTotal == 22) //----Checks to see if you got 2 A's
		{
			pTotal = 12;
			
		}
		
		//--------------------------------------------Player Hit or Stay loop
		i = 3;
		do {
			if(blackJack == 1)
			{
				break;
			}
			
			
			do{
			playerResponce = 0; //----reset player response to null to avoid inf loop.
			printf(" // **Press 'h' for 'Hit' or 's' to Stay:");	
			scanf("%c", &playerResponce);
			getchar();// --- removes any extra stuff in scanf buffer
			}while(playerResponce != 's' && playerResponce != 'h');
			
			if(playerResponce == 's')
			{
				displayHideFirstTime = 0;
				break;
			}
			
			if (playerResponce == 'h')
			{
				displayHideFirstTime = 0;
				playerCards[i] = '-';
				i++;
				playerCards[i] = mixDeck[nextCard];
				i++;
				playerCards[i] = '\0';
				
				pCharToInt(&pTotal,&pReduceAceValueToOne, mixDeck[nextCard]);
				printf("\n");
				printf("----------------------------------\n");
				
				
				
				if (displayHideFirstTime == 0) // avoids duplicating cosole printf
				{
					printf("Player cards %s total = %d \n",playerCards ,pTotal);
					displayHideFirstTime = 0;
				}
				
				if (pTotal > 21)  // Checks for Ace to reduce pTotal
				{
					for(checkForAce = 0; i < playerCards[checkForAce]; checkForAce++ ){
						if (playerCards[checkForAce] == 'A')
						{
							pAcesFound++;
							if(pAcesFound > pReduceAceValueToOne)
							{
								pReduceAceValueToOne++;
								pTotal -= 10;
								break;
							}
						}
					}
				}
				pAcesFound = 0; //--- resets the Ace counter		

				
				
				if (pTotal > 21)
				{
					sleep(1);
					printf("Player cards %s total = %d ",playerCards ,pTotal);
					printf("// **** YOU BUSTED YOUR HAND****\n\n");
					dWin++;
					pBust = 1;
					break;
				}
				printf("----------------------------------\n");
				
				
				nextCard++;
				
			}
		}while ((playerResponce != 'h') || (playerResponce != 's'));
		printf("\n");
		
//---------------------------------------------------------------- Computers hand	
		i = 3;
		do{
			
			if (pBust == 1) //-- checks to see if player busted
			{
				break;
			}
			if (blackJack == 1) //-- checks to see if player got blackjack
			{
				break;
			}
			printf("\n");
			printf("----------------------------------\n");
			printf("----> Dealer Cards %s total = %d \n", dealerCards,dTotal);
			printf("----------------------------------\n");
			if (dTotal < 17)
			{
				sleep(1);
				dealerCards[i] = '-';
				i++;
				dealerCards[i] = mixDeck[nextCard];
				i++;
				dealerCards[i] = '\0';
				
				dCharToInt(&dTotal,&dReduceAceValueToOne, mixDeck[nextCard]);
				nextCard++;
				printf("----> Dealer Cards %s total = %d \n", dealerCards,dTotal);
			
			}
			if (dTotal > 21)  // Checks for Ace to reduce dTotal
			{
				for(checkForAce = 0; i < dealerCards[checkForAce]; checkForAce++ ){
					if (dealerCards[checkForAce] == 'A')
					{
						dAcesFound++;
						if(dAcesFound > dReduceAceValueToOne)
						{
							dReduceAceValueToOne++;
							dTotal -= 10;
							break;
						}
					}
				}
			}
			dAcesFound = 0; //--- resets the Ace counter
			
			if(dTotal > 21)
			{
				printf("*****DEALER BUSTED YOU WIN****\n\n");
				pWin++;
				printf("-------------------------\n");
				dBust = 1;
				break;
			}
		}while(dTotal < 17);
		
		while( pBust != 1){
			if(blackJack == 1)
			{
				break;
			}
			if(dBust == 1)
			{
				break;
			}
			
			
			if(pBust == 1 || dBust == 1)
			{
				break;
			}
			if(dTotal == pTotal)
			{
				printf("\n");
				printf("------> WE PUSHED\n");
				break;
			}
			if (dTotal > pTotal)
			{
				printf("\n");
				printf("------> DEALER WINS <------\n");
				dWin++;
				break;
			}	
			if(dTotal < pTotal)
			{
				printf("\n");
				printf("------> YOU WIN <-----\n");
				pWin++;
				break;
			}
		}
		displayHideFirstTime = 1;
	}while(gameCount < 5);
	
//------------------------------------------------ Print results of the game
	if (pWin == dWin)
	{
		printf("*** GAME OVER ***\n\n");
		printf("***<WE TIED -- me %d - you %d >****\n", dWin,pWin);
	}
	if (pWin> dWin)
	{
		printf("*** GAME OVER ***\n\n");
		printf("---> YOU WON -- you won %d - I won %d - I must power down in shame\n",pWin, dWin);
	}
	if (pWin < dWin)
	{
		printf("*** GAME OVER ***\n\n");
		printf("----< I WON -- I won %d Games- you won %d games>- learn to program better", dWin, pWin);
	}
		
	return 0;
}

void pCharToInt(int *pTotal,int *pReduceAceValueToOne, char card)
{
	int i;
	
	switch (card) {
		case '2':
			i = 2;
			break;
		case '3':
			i = 3;
			break;
		case '4':
			i = 4;
			break;
		case '5':
			i = 5;
			break;
		case '6':
			i = 6;
			break;
		case '7':
			i = 7;
			break;
		case '8':
			i = 8;
			break;
		case '9':
			i = 9;
			break;
		case 'T':
			i = 10;
			break;
		case 'J':
			i = 10;
			break;
		case 'Q':
			i = 10;
			break;
		case 'K':
			i = 10;
			break;
		case 'A':
			if (*pTotal>= 11) 
			{
				i = 1;
			}
			else 
			{
				i = 11;
			}
			break;
		default:
			i = 9999;
			break;
			
	}
	
	if (card == 'A')
		if (i == 1)
		{
			*pReduceAceValueToOne = (*pReduceAceValueToOne + 1);
		}

		*pTotal = *pTotal + i;
}
void dCharToInt(int *dTotal, int *dReduceAceValueToOne, char card)
{
	int i;
	
	switch (card) {
		case '2':
			i = 2;
			break;
		case '3':
			i = 3;
			break;
		case '4':
			i = 4;
			break;
		case '5':
			i = 5;
			break;
		case '6':
			i = 6;
			break;
		case '7':
			i = 7;
			break;
		case '8':
			i = 8;
			break;
		case '9':
			i = 9;
			break;
		case 'T':
			i = 10;
			break;
		case 'J':
			i = 10;
			break;
		case 'Q':
			i = 10;
			break;
		case 'K':
			i = 10;
			break;
		case 'A':
			if (*dTotal>= 11) 
			{
				i = 1;
			}
			else 
			{
				i = 11;
			}
			break;
		default:
			i = 9999;
			break;
			
	}
	if (card == 'A')
		if (i == 1)
		{
			*dReduceAceValueToOne = (*dReduceAceValueToOne + 1);
		}
	
	*dTotal = *dTotal + i;
}

Thanks for your help.

-Lars
 

McGordon

macrumors member
Dec 28, 2010
63
1
Scotland
The problem I could not solve yet is the 'do while' loop for the "Press 'h' to hit or 's' to stay". If I just hit the return key with no value first it is in an endless loop that I can't get out of even if I enter a value and hit return again.

I think you could make it a bit simpler and just have an infinite loop which
waits on reading either an 'h' or a 's':
Replace this:
Code:
   do{
      playerResponce = 0; //----reset player response to null to avoid inf loop.
      printf(" // **Press 'h' for 'Hit' or 's' to Stay:");	
      scanf("%c", &playerResponce);
      getchar();// --- removes any extra stuff in scanf buffer
   }while(playerResponce != 's' && playerResponce != 'h');


With this:
Code:
    printf(" // **Press 'h' for 'Hit' or 's' to Stay:");	
    do{
       scanf("%c", &playerResponce);
    }while(playerResponce != 's' && playerResponce != 'h');

I've removed the getchar() as your program can get out of sync, with the carriage return being read into playerResponce and the character you want which might be 'h' or 's' is getting read and ignored by getchar(). Now it ignores everything but 'h' and 's' and loops infinitely until it reads one of those.

scanf still isn't great and never works for "press 'h'" as you have to press enter to get it read. Maybe change your printf to instruct the player to type 'h' or 's' then return. Also you could type "hhhhh"<return> and your program would read it as the player hitting 5 times in a row.
 

balamw

Moderator emeritus
Aug 16, 2005
19,366
979
New England
Just a quick reaction.

dCharToInt and pCharToInt are exactly the same code. Since you are passing the player/dealer specific variables by reference (pointer) you can replace those calls with a common call.

Code:
dCharToInt(&dTotal,&dReduceAceValueToOne, mixDeck[nextCard]);
gives the exact same response as
Code:
pCharToInt(&dTotal,&dReduceAceValueToOne, mixDeck[nextCard]);

So consider replacing the two functions with a common one.


Also, for clarity, I would pass the player/dealer cards instead of the cards from the deck. (A good habit for later object oriented programming).

Code:
playerCards[0] = mixDeck[nextCard];
pCharToInt(&pTotal,&pReduceAceValueToOne, [B]playerCards[0][/B]);
nextCard++;

B
 

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
McGordon - That is a great idea. So basically I am just putting the scanf into a inf loop until it gets the correct response. I am guessing this also handles the RETURN key if that is all that is entered with no value. I will plug it in and try it.

balamw - I am going to go back and refine it. It was easier for me to separate the dealer from the player at first. What you suggested I had in the back of my mind but didn't want to confuse myself at first.

What I want to do as I continue in the book is to keep refining this code. I am starting on Structs and will see if I can make some of this code go into separate .h files to make it look better and more readable.

Thanks again everyone, Learning C is starting to be a fun project.
 

balamw

Moderator emeritus
Aug 16, 2005
19,366
979
New England
balamw - I am going to go back and refine it. It was easier for me to separate the dealer from the player at first. What you suggested I had in the back of my mind but didn't want to confuse myself at first.

Yeah, as I said it was a first reaction to your code. Definitely nothing wrong with having two functions that do the same thing.

It'll be a while as you work through C and Pascal, but as you get into object oriented programming you will want to reuse code as often as possible. So I'm trying to encourage you to think that way as you look at your own code.

A simple rule of thumb I like to keep in mind is when I feel the desire to cut and paste more than about 5 lines of code, design for re-use instead. The common switch/case statement in your player/dealer functions would drive me to look to define a common function.

B
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
I'd been meaning to comment but hadn't gotten a chance to look at this yet. I just eye-balled on my phone, I didn't compile or run, but here are my notes:
The shuffling could take until the end of geologic time to complete. It probably won't, but it would be worth refining.

Why is index 1 of dealerCards and playerCards unused? Why do you skip a position in these each time a card is added? A hand can have up to 11 cards, you have room for 14, but only use every other position, so you don't have room for a full hand.

mixDeck[53] = '\0'; overflows mixDeck. 0-52 are the valid indexes.

There is a keyword 'continue' that will let you cycle a loop. If a player gets blackjack or busts you can use this and greatly simplify the later logic.

You have two routines (which you know are duplicated) to deal with a new card. You then have logic you stated is a bit convoluted to deal with aces. Why not just pass the hand to a routine and calculate the "best value"? Then all the ace hootenanny will be isolated there. A local numAces that counts, summing using 11 to begin with, then decrementing numAces while it is > 0 and the value is > 21 and decrementing the value by 10 each time seems like a way to do it. Encapsulating this logic should be a helpful exercise. Keeping related logic self-contained is much better than it being littered about.

Shouldn't you keep a pushCount that is incremented on a push and set to 0 when a hand is won? You would then increment the win count by 1 + pushCount. Since you have a fixed number of hands, pushing on the fifth gets tricky. You'd also eventually run out of cards and need to reshuffle (maybe shuffleDeck needs its own function?) if you allowed pushes to continue until a win.

While you didn't attempt it at all, in a future revision you might want to add an option to split when your first two cards match.

It would take a little doing, but it might be nice to let the user pick a position (0-51 to make it easy for you, or just 1-52 and you have to subtract) to cut the deck. I envision doing this with some temporary storage in a shuffleDeck function.

-Lee
 
Last edited:

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
Hi Lee thanks for looking at it!

Why is index 1 of dealerCards and playerCards unused?
They are used. I added them later when I was writing the program to printf to the screen with the number and a '-' between the numbers. More importantly, I use them to keep track of the 'A' (Ace's) that were dealt to the Dealer and Player. If the pTotal was over 11 and an ace is drawn I need a way to check to see if the 'A' was were already reduced to a value of 1 instead of 11.

mixDeck[53] = '\0'; overflows mixDeck. 0-52 are the valid indexes.
Opps, I will fix this.

A local numAces that counts, summing using 11 to begin with, then decrementing numAces while it is > 0 and the value is > 21 and decrementing the value by 10 each time seems like a way to do it.
Thanks You :) I wrote the program in 10 hours. The next day I woke up and played it and the first had I got were two A's and it said I busted. I them remembered A's had a value of 1 or 11. It took me 20 hours to solve that problem and the code grew a lot!
Shouldn't you keep a pushCount that is incremented on a push and set to 0 when a hand is won? You would then increment the win count by 1 + pushCount. Since you have a fixed number of hands, pushing on the fifth gets tricky. You'd also eventually run out of cards and need to reshuffle (maybe shuffleDeck needs its own function?) if you allowed pushes to continue until a win.
I limited the games to 5 avoid running out of cards. I didn't think keeping a push count was important because if we push I would just write we pushed.
While you didn't attempt it at all, in a future revision you might want to add an option to split when your first two cards match.
I thought of that before I started the program. Since there was no money to be won or lost I saw no reason to add a Split or Double Down feature. As I keep revising it I might switch from game count limit to a "If your have $0 money left limit.

I needed a little break from the book to see what I could do so the past few days was about making this program that I will continue to refine and make better and smaller. I am starting on the book not and will start with Structs.

Thanks for your input Lee210!

-Lars
 

dmi

macrumors regular
Dec 21, 2010
162
33
Code:
        char mixDeck[53];
        mixDeck[53] = '\0';
This has been mentioned before, but as the error has been repeated,
it apparently wasn't emphasized enough.

If the result points one past the last element of the array object, it
shall not be used as the operand of a unary * operator that is evaluated.
When a shall not requirement is violated the behavior in undefined,
which means that nothing in the erroneous program can be depended on.
Anything the erroneous program does that's undesirable, could have been caused but the undefined behavior, regardless of anything you do to other parts of the program to fix.
Anything the program does that's desireable, could stop the next time you run a program with undefined behavior.
So even if you get lucky and the effect of the undefined behavior is that the situation is ignored completely, you are asking for trouble as long as you keep doing this.

By the way, although you could remove this problem with either a change to
char mixDeck[54];
or to
mixDeck[52] = '\0';
the assignment seems to be pointless anyway because mixDeck does not appear to be passed to printf or to any other string function that r4equires a null terminator.
 

dmi

macrumors regular
Dec 21, 2010
162
33
Code:
                randNumberRoll = rand() % (deck);
                do{
                        if (cards[randNumberRoll] == '-')
                                randNumberRoll = rand() % (deck);
                }while(cards[randNumberRoll] == '-');
Although this may not be the most efficient way to do a a shuffle,
the above method does work, and the shuffle would be fair, assuming that rand() is sufficiently random.
But the code is curiously redundant, since it seems to be equivalent to
Code:
                do{
                                randNumberRoll = rand() % (deck);
                }while(cards[randNumberRoll] == '-');
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
A few more comments based on your reply:
If you do intend to skip positions so the array is used for display purposes, it is too short to hold the largest possible hand. I'm going by values only, not by permutations to get there (so it may be impossible but I'd code defensively or work out the permutations if storage is at a massive premium). The most cards would be four aces, four twos, and three threes. This is 11 cards, so you need 11 positions for these, 10 for intermediate -s, and one for a null terminator. This is 22 which is greater than the 15 you have allotted. The dealer staying above 16 means he won't hit on some values, so I believe 10 is the largest dealer hand, but it is probably easier to have room for 11 in both hands. It's impossible for both players to have this many cards, but you don't know who might so I'd just allow 11 for both.

With that being said, you may want to consider a more concise storage mechanism that is not displayed directly. This will allow more straight-forward logic for storing your hand, which could then be passed to a short function that will add the intermediate dashes for you. This way if you want spaces, *s, etc instead of dashes it's one simple change in the display routine instead of many changes throughout your code. Breaking up the storage and logic for your algorithms from your display logic is simply the right thing to do. This is a simple case, and your logic is harder to follow due to your bending of your data structures to fit the needs of the display. For any non-trivial case this will be amplified. If you segregate your algorithms/"business logic" from your display code, it makes things more readable and easier to maintain. If you wanted to add a GUI, for example, doing so when you have a clear distinction between logic and display is much easier.

The pushCount idea was just something I was throwing out there. I read up and see that it is standard for the bet to be returned on a push. I was thinking the bet was pushed forward to the next hand, which would have a new bet as well. That's why I made the suggestion of "pushing" the win "token" forward, but in light of what I read that makes less sense.

Keep it up, and stay excited. Taking a break from your book and working on something interesting to you was a stellar idea. Staying interested and excited is key, and putting new concepts into practice is vital for retention, IMO. The reinforcement afforded by putting a concept into practice is crucial, and the reward of a working whatsit can give you a much-needed boost whilst slogging through new material.

-Lee
 

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
Lee210
Breaking up the storage and logic for your algorithms from your display logic is simply the right thing to do. This is a simple case, and your logic is harder to follow due to your bending of your data structures to fit the needs of the display.

I never even considered this approach and I am pondering how to do this? Would I try to do more Storage and Logic out side of main() using Functions and Structs? Leaving me main to deal more with the display part of the program? In other words, send the data off to be processed, then return the result back to main() for display?

DMI - ya... I still have not changed it but will tonight :)

-Lars
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
Lee210


I never even considered this approach and I am pondering how to do this? Would I try to do more Storage and Logic out side of main() using Functions and Structs? Leaving me main to deal more with the display part of the program? In other words, send the data off to be processed, then return the result back to main() for display?

DMI - ya... I still have not changed it but will tonight :)

-Lars

How much or how little goes in main is really a preference, though as you encapsulate various things in functions you'll probably end up with less and less there. In Cocoa GUI apps main calls one other function. This is one end, where you are is near the other. I wouldn't make a judgement about what's better, there are a lot of ways to do things, but I guess when it comes down to it modularity and encapsulation tend to be better, so that will lend itself to less and less code in main.

My thought for this program would be, without radical redesign, to just store the character representing a card in an array, perhaps with a terminator (null is fine) perhaps with a count in another variable. Then when you need to display this, you'd pass the array (and count, if applicable) to showHand. This would loop over the hand, printing one card and one delimiter at a time. Maybe it could check if it was on the last card and omit the delimiter.

As you break down tasks into functions (shuffleDeck, dealCard, getBestValueForHand, displayHand, getHitOrStandFromUser,etc.) you would naturally migrate code from main into functions that group/encapsulate related code, and main would turn into a pretty short function with some high-level gamestate that passes it to functions for each task. It would read, more or less, as you would describe a game at the highest level. Each function would do one thing. At the current level you would probably only call your own functions from main, and they would probably not call one another (though you will get there soon).

The thrust of breaking things down is to do a very basic thing, be sure to do it right, and be able to reuse that thing. When dealing a card, who cares who it's to? When getting the best value for a hand, who cares whose hand it is? Conversely, when storing a hand who cares if you show - or # between each card when you display it?

If your book is a beginning programming book hopefully it teaches some of these principals along with the nitty-gritty of C syntax. It's a lot to get your head around, but how to think about a problem, break it down, then build the smaller parts into a working solution to the problem are the things that carry through to all levels and styles of programming. From there, general program flow and control structures will carry through to other iterative languages including object-oriented languages. The specific syntax of declaring a variable or referencing a member of a structure may only apply to C or its close relatives, but those small syntactical details are the finest bits of a language that are easy and fast to pick up when you learn a new language. Learning to think, classify problems, write so others (including future you) can quickly understand structure and intention, apply algorithms, code defensively, quickly identify bugs by "feel", etc. are the things that take time and apply universally.

In any event, keep chugging. The only way to get better is to keep learning and doing.

-Lee
 

chrono1081

macrumors G3
Jan 26, 2008
8,463
4,185
Isla Nublar
Kind of off topic and you may have already done it (sorry I didn't look at your code closely) but look up the ASCII table and you can add "graphics" to your cards. There are ASCII characters that are a heart, spade, club, and diamond :)
 

balamw

Moderator emeritus
Aug 16, 2005
19,366
979
New England
The thrust of breaking things down is to do a very basic thing, be sure to do it right, and be able to reuse that thing. When dealing a card, who cares who it's to? When getting the best value for a hand, who cares whose hand it is? Conversely, when storing a hand who cares if you show - or # between each card when you display it?

Well put.

I've worked with plenty of code where people don't follow these basic principles where sections of repeated code, that are supposed to do the same thing, evolve away from each other because of lack of modularity and reuse to the point where things break and it becomes harder to suss problems out given that there are multiple locations where it could have broken. Or where many disparate functions are lumped together and it becomes increasingly difficult to separate the functions.

B
 

z0rt

macrumors newbie
Jan 3, 2011
5
0
This is a bit more math-oriented but you should also note that the maximum hand size of a player can never be greater than 11 (assuming no split) since four aces valued at one each, plus four twos and three threes equals twenty-one.
 

chrono1081

macrumors G3
Jan 26, 2008
8,463
4,185
Isla Nublar
No, there are not.
But there are Unicode characters that a heart, spade, club, and diamond

Oops! Sorry about that! :D Its been ages ago since I made a console black jack game and I remember doing that for mine. (I just don't remember what I did to do it :p)
 

Sydde

macrumors 68030
Aug 17, 2009
2,552
7,050
IOKWARDI
This is a bit more math-oriented but you should also note that the maximum hand size of a player can never be greater than 11 (assuming no split) since four aces valued at one each, plus four twos and three threes equals twenty-one.

I seem to recall that many or most blackjack games define a hand of five cards that do not bust as a winner just because of its low probability.
 

ulbador

macrumors 68000
Feb 11, 2010
1,554
0
I seem to recall that many or most blackjack games define a hand of five cards that do not bust as a winner just because of its low probability.

This may be the case with friendly and computer games, but I've never seen this in a casino...
 

balamw

Moderator emeritus
Aug 16, 2005
19,366
979
New England
This may be the case with friendly and computer games, but I've never seen this in a casino...

Isn't that partially because most casinos deal from multiple decks, not just one. The 11 card limit z0rt mentions is only for a single deck.

If you have enough decks, you could in principle be dealt all aces.

B
 

ulbador

macrumors 68000
Feb 11, 2010
1,554
0
Isn't that partially because most casinos deal from multiple decks, not just one. The 11 card limit z0rt mentions is only for a single deck.

If you have enough decks, you could in principle be dealt all aces.

B

That could be true. I know I've seen two deck blackjack, but I've never played it (and the chances are slim of actually pulling 5 cards so I doubt I would have seen it)
 

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
Lee210 - Thanks again for the detailed explanation. I have a few more questions but I will wait until I finish the book and begin to refine the Black Jack game. My goal is to make good readable code and make things easier on my to move tasks in to functions or routines.

I am really thankful to everyone's help here. Without this forum it would be very difficult to learn C and get useful tips.

Thanks you all!!!

-Lars
 

z0rt

macrumors newbie
Jan 3, 2011
5
0
@ulbador:

As balamw said, the note I mentioned works for a single deck. I did it based off of a single deck since that's what was specified in the code.

Anyway, the point I wanted to make is that BlackJack has many variants. The majority of the casinos I've gambled at use six decks as a base. There's one casino in northern California where they use 8 decks and actually take out many of the twos and threes. I can't say which one this was because my friend's friend was working there.

Regarding code, I would stay away from srand(clock()) and instead opt for srand(time(NULL)). Remember, though, that the type returned by time() is time_t.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,753
8,443
A sea of green
Regarding code, I would stay away from srand(clock()) and instead opt for srand(time(NULL)). Remember, though, that the type returned by time() is time_t.

I would stay away from srand() altogether; it's a bad random number generator, and you can tell because its man page says so. arc4random() is much better.

Not that I think it matters for a toy program. Just saying that anyone trying to "improve" srand() by carefully picking parameters is already in a state of sin.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.