Executive Summary

You will implement a fully functioning game of Blackjack. No prior knowledge of the game is needed. However, you will need to know what cards appear in a standard deck of playing cards. See your instructor if you have any questions on that account.

Blackjack (also called "21") is basically a game between an individual player and a dealer. There's a gambling side to the game that this project does not address. The project simply plays the game with the user as "Player" and program as "Dealer", and determines the winner and loser.

Honor: The course policy and the instructions it references, most pertinently COMPSCIDEPTINST 1531.1C, spell out what kinds of assistance are permissable for programming projects. The instructor can give explicit permission for things that would otherwise not be allowed. For this project, you have explicit permission
  1. to get help from another current IC210 instructor as well as your own (any assistance must be documented though), and
  2. to use general purpose C++ resources online (though such use must be documented). Resources that might specifically address this project, code that implements blackjack or other card games, are not allowed. You are very specifically not allowed to look at previous semesters' IC210 programming projects that may have addressed similar issues.
Combining the instructions referenced in the course policy and the explicit permissions above, and what you get is summarized as:

Part 1 [Up to 15pts] - Name your source code file part1.cpp

A part 1 solution will read in a deck of cards from a file (more on that momentarily) and print out integer representations (also described later) for each card in the deck, in the order they appear in the file. A correct solution must store the integer representations of the 52 cards in an array, and only after that print the output. Otherwise its use in working towards the remaining steps of the project is limited. When the program runs, it will prompt the user to choose a deck (as shown below). If the user enters anything other than "new", the program will attempt to read a deck from a file of that name (printing an error message if the file is not found). If the user enters "new", the program will run "newdeck" to create a newly shuffled deck and store it in a file tmp.deck via the statement system("./newdeck > tmp.deck"); (you'll need to #include cstdlib) then open and read from tmp.deck.
  1. The sample shuffled deck files are named d06, d38, d55, d56, d57, d58, d59, d88, and there is a program named newdeck that you will use to create new randomly shuffled decks. These must be downloaded and stored within your project directory with the following command:
    curl -O http://rona.academy.usna.edu/~wcbrown/p2.tar ; tar xf p2.tar ; chmod 500 ./newdeck
  2. Our Unix terminal program understands "UTF-8" character encodings, which means we can print card suit symbols to the screen. Here are the suits and the corresponding string for printing them in unicode: ♣ ← "\u2663", ♦ ← "\u2666", ♥ ← "\u2665", ♠ ← "\u2660". You will have to both write and read suits represented this way. For example, input file d55 looks like this when you cat it to the terminal:
    ~/$ cat d55
    4♥ Q♥ 10♠ 5♥ 5♦ 7♦ 7♠ 5♣ 3♠ 2♥ 3♦ J♠ 6♥ 4♦ A♥ Q♠ A♠ 3♥ 3♣ 9♥ J♣ K♦ 7♣ 5♠ A♦ 2♦ Q♣ 8♥ K♣ 10♥ K♥ 8♠ J♦ 7♥ 9♠ 4♣ 10♦ J♥ 8♦ 2♣ 4♠ K♠ Q♦ 6♦ 2♠ 9♣ 8♣ 6♣ 10♣ 6♠ A♣ 9♦
    
    When you read in a "suit" as a string like this: cin >> s;, you can determine whether the suit was, for example, diamonds, by testing: if (s == "\u2666") .... Conversely, if you want to print out a diamonds suit symbol, you could simply do this: cout << "\u2666";.
  3. Representing cards given what we know so far is tricky, because there are two parts to a card — its face value and its suit. So, to represent a card as as single number (I call it the "cardvalue") I recommend you use the following trick.
    1. represent suits by number according to these rules: 0 = ♣, 1 = ♦, 2 = ♥, 3 = ♠
    2. represent face values according to these rules: 2 = 2, 3 = 3, ..., 10 = 10, 11 = J(jack), 12 = Q(queen), 13 = K(king), 14 = A(ace)
    3. represent a card as a number by the rule: cardvalue = 4 × facevalue + suit and (facevalue=cardvalue/4, suit = cardvalue%4)
      So, for example, the card Q♥ → (facevalue=12,suit=2) → 4×12 + 2 = 50
      In the other direction, cardnumber 59 = 4×14 + 3 (i.e. 59/4=14, 59%4=3) → (facevalue=14,suit=3) → A♠
Sample runs: red text represents user input, gray text is explanatory and not part of the output
~/$ ./p1
choose deck> d55 
18 ← 4*4 + 2 ← 4♥
50 ← 4*12 + 2 ← Q♥
43 ← 4*10 + 3 ←10♠
⋮
27 ← 4*6 + 3 ← 6♠
56 ← 4*14 + 0 ← A♣
37 ← 4*9 + 1 ← 9♦
~/$ ./p1
choose deck> d56
36 ← 4*9 + 0 ← 9♣
27 ← 4*6 + 3 ← 6♠
10 ← 4*2 + 2 ← 2♥
⋮
49 ← 4*12 + 1 ← Q♦
18 ← 4*4 + 2 ← 4♥
39 ← 4*9 + 3 ← 9♠
~/$ ./p1
choose deck> d99
File "d99" not found!
$ ./p1
choose deck> new
42
36
21 DIFFERENTEVERY TIME
20 YOU RUN IT
57
29

Part 2 [Up to 30pts] - Name your source code file part2.cpp

A part 2 solution should be exactly like the part 1 solution except that instead of printing the integer "cardvalues", you will print proper cards, e.g. instead of the integer 50 you'll print out the card Q♥. The only catch is that what you print out needs to be right justified, i.e. all the suit values (which come second) have to line up in the same column.

Sample runs: red text represents user input, gray text is explanatory and not part of the output
~/$ ./p2
choose deck> d58
 J♥
 9♥
 4♥
 ⋮
 3♦
 9♦
 8♣
~/$ ./p2
choose deck> d88
 J♥
 J♦
 A♣
 ⋮
10♠
 4♣
 5♥
~/$ ./p2
choose deck> d60
File "d60" not found!
$ ./p2
choose deck> new
 6♠
 Q♠
 8♦ DIFFERENTEVERY TIME
10♦ YOU RUN IT
 7♠
 8♠
Note: to be a proper Part 2 solution, your code must first store the cards read from the file as integers (as per Part 1), and afterwards print the cards based on those integer values stored in the array. Once again, doing it otherwise (perhaps by reading the file twice) will not provide a helpful base for proceeding to later Parts.

Part 3 [Up to 50pts] - Name your source code file part3.cpp

A correct part 3 solution will simulate dealing cards to a "Player" and a "Dealer" in the following order: deal two cards to "Player", then deal two cards to "Dealer", then display (as shown below). Then three rounds of dealing first one card to "Player", then one card to "Dealer", then displaying the hands (once again as shown below). Note that the "top" of the deck is the first card from the deck file, and you must deal from the top of the deck (in the Old West, people got shot for violating this rule!). Thus, your program's output really must match what is shown below for the given examples.

Sample runs: red text represents user input, gray text is explanatory and not part of the output
~/$ ./p3 
choose deck> d55 
                 ← deck is: 4♥ Q♥ 10♠ 5♥ 5♦ 7♦ 7♠ 5♣ 3♠ 2♥ 3♦ J♠ ...
 Player Dealer
|  4♥  | 10♠  |
|  Q♥  |  5♥  |
                 ← deck is: 4♥ Q♥ 10♠ 5♥ 5♦ 7♦ 7♠ 5♣ 3♠ 2♥ 3♦ J♠ ...
 Player Dealer
|  4♥  | 10♠  |
|  Q♥  |  5♥  |
|  5♦  |  7♦  |
                 ← deck is: 4♥ Q♥ 10♠ 5♥ 5♦ 7♦ 7♠ 5♣ 3♠ 2♥ 3♦ J♠ ...
 Player Dealer
|  4♥  | 10♠  |
|  Q♥  |  5♥  |
|  5♦  |  7♦  |
|  7♠  |  5♣  |
                 ← deck is: 4♥ Q♥ 10♠ 5♥ 5♦ 7♦ 7♠ 5♣ 3♠ 2♥ 3♦ J♠ ...
 Player Dealer
|  4♥  | 10♠  |
|  Q♥  |  5♥  |
|  5♦  |  7♦  |
|  7♠  |  5♣  |
|  3♠  |  2♥  |
~/$ ./p3
choose deck> d56  

 Player Dealer
|  9♣  |  2♥  |
|  6♠  |  Q♥  |

 Player Dealer
|  9♣  |  2♥  |
|  6♠  |  Q♥  |
|  A♠  |  2♦  |

 Player Dealer
|  9♣  |  2♥  |
|  6♠  |  Q♥  |
|  A♠  |  2♦  |
|  J♠  |  4♣  |

 Player Dealer
|  9♣  |  2♥  |
|  6♠  |  Q♥  |
|  A♠  |  2♦  |
|  J♠  |  4♣  |
|  A♦  |  5♠  |
~/$ ./p3
choose deck> d57  

 Player Dealer
|  2♦  |  8♠  |
|  8♥  |  3♦  |

 Player Dealer
|  2♦  |  8♠  |
|  8♥  |  3♦  |
|  K♦  |  J♦  |

 Player Dealer
|  2♦  |  8♠  |
|  8♥  |  3♦  |
|  K♦  |  J♦  |
|  8♦  |  5♣  |

 Player Dealer
|  2♦  |  8♠  |
|  8♥  |  3♦  |
|  K♦  |  J♦  |
|  8♦  |  5♣  |
|  K♣  |  K♠  |

Note: You really want to have your program simulate dealing a card to a hand. You should be able to point to few variables and say "those represent the player's hand", and point to a few more and say "those represent the dealer's hand".

Part 4 [Up to 70pts] - Name your source code file part4.cpp

A correct part 4 solution will start to play something that actually looks like a game. Player and Dealer will both be dealt two cards (as in part 3). But then the program will proceed to ask the Player and Dealer in turns whether they want to "hit" (in which case they get dealt another card into their hand), or to "stand" in which case their hand stays the same. The player goes first, and the program should go through three rounds (i.e. the Player and the Dealer both get three turns). In between rounds (i.e. just before printing out the current hands), make the call system("clear"); to clear the terminal window, so that only the current state of the game is showing at any given time. Below is an example of how a game might play out. Your output and the way you get input from the user must match what's shown here.

Sample run: red text represents user input
~/$ ./p4
choose deck> d58  
 Player Dealer
|  J♥  |  4♥  |
|  9♥  |  K♦  |
Round 1 Player's turn
hit or stand? [h/s] h  
 Player Dealer
|  J♥  |  4♥  |
|  9♥  |  K♦  |
| 10♦  |      |
Round 1 Dealer's turn
hit or stand? [h/s] h  
 Player Dealer
|  J♥  |  4♥  |
|  9♥  |  K♦  |
| 10♦  |  9♣  |
Round 2 Player's turn
hit or stand? [h/s] s  
 Player Dealer
|  J♥  |  4♥  |
|  9♥  |  K♦  |
| 10♦  |  9♣  |
Round 2 Dealer's turn
hit or stand? [h/s] h  
 Player Dealer
|  J♥  |  4♥  |
|  9♥  |  K♦  |
| 10♦  |  9♣  |
|      |  Q♥  |
Round 3 Player's turn
hit or stand? [h/s] s  
 Player Dealer
|  J♥  |  4♥  |
|  9♥  |  K♦  |
| 10♦  |  9♣  |
|      |  Q♥  |
Round 3 Dealer's turn
hit or stand? [h/s] h  
 Player Dealer         
|  J♥  |  4♥  |
|  9♥  |  K♦  |
| 10♦  |  9♣  |
|      |  Q♥  |
|      | 10♠  |

Part 5 [Up to 85pts] - Name your source code file part5.cpp

A correct part 5 solution should behave exactly like a correct part 4 solution, except that in each round the current "best scores" for both Player and Dealer hands should be shown. The "best score" for a hand is computed according to the following rules. Add up points for each card in the hand, where aces are worth one point, kings, queens and jacks are worth 10 points, and numbered cards (i.e. 2 though 10) are worth their number in points. Call this number total. If the hand has no aces, total is the "best score" for the hand. If there are aces in the hand, and total + 10 is not greater than 21, the "best score" is total + 10. Otherwise, "best score" is simply total.

Sample run: red text represents user input
$ ./p5 
choose deck> d37  
 Player Dealer
|  4♣  |  A♥  |
|  J♦  |  2♦  |
Player 14, Dealer 13
Round 1 Player's turn
hit or stand? [h/s] s  
 Player Dealer
|  4♣  |  A♥  |
|  J♦  |  2♦  |
Player 14, Dealer 13
Round 1 Dealer's turn
hit or stand? [h/s] h  
 Player Dealer
|  4♣  |  A♥  |
|  J♦  |  2♦  |
|      | 10♣  |
Player 14, Dealer 13
Round 2 Player's turn
hit or stand? [h/s] s  
 Player Dealer
|  4♣  |  A♥  |
|  J♦  |  2♦  |
|      | 10♣  |
Player 14, Dealer 13
Round 2 Dealer's turn
hit or stand? [h/s] h  
 Player Dealer
|  4♣  |  A♥  |
|  J♦  |  2♦  |
|      | 10♣  |
|      |  5♣  |
Player 14, Dealer 18
Round 3 Player's turn
hit or stand? [h/s] h  
 Player Dealer
|  4♣  |  A♥  |
|  J♦  |  2♦  |
|  4♠  | 10♣  |
|      |  5♣  |
Player 18, Dealer 18
Round 3 Dealer's turn
hit or stand? [h/s] h  
 Player Dealer         
|  4♣  |  A♥  |
|  J♦  |  2♦  |
|  4♠  | 10♣  |
|      |  5♣  |
|      |  6♣  |
Player 18, Dealer 24

Part 6 [Up to 95pts] - Name your source code file part6.cpp

A part 6 solution functions just like a part 5 solution with the following two exceptions:

Sample run: red text represents user input
$ ./p6
choose deck> d55  
 Player Dealer
|  4♥  | 10♠  |
|  Q♥  |  5♥  |
Player 14, Dealer 15
Round 1 Player's turn
hit or stand? [h/s] s  
 Player Dealer
|  4♥  | 10♠  |
|  Q♥  |  5♥  |
Player 14, Dealer 15
Round 1 Dealer's turn
hit or stand? [h/s] h  
 Player Dealer
|  4♥  | 10♠  |
|  Q♥  |  5♥  |
|      |  5♦  |
Player 14, Dealer 20
Round 2 Player's turn
hit or stand? [h/s] h  
 Player Dealer
|  4♥  | 10♠  |
|  Q♥  |  5♥  |
|  7♦  |  5♦  |
Player 21, Dealer 20
Round 2 Dealer's turn
hit or stand? [h/s] s

Note: The game stops
because of consecutive
"stand" moves.
 Player Dealer
|  4♥  | 10♠  |
|  Q♥  |  5♥  |
|  7♦  |  5♦  |
Player 21, Dealer 20
Round 3 Player's turn
hit or stand? [h/s] s
 Player Dealer
|  4♥  | 10♠  |
|  Q♥  |  5♥  |
|  7♦  |  5♦  |
Player 21, Dealer 20

Sample run: red text represents user input
$  ./p6 
choose deck> d58    
 Player Dealer
|  J♥  |  4♥  |
|  9♥  |  K♦  |
Player 19, Dealer 14
Round 1 Player's turn
hit or stand? [h/s] h  
 Player Dealer
|  J♥  |  4♥  |
|  9♥  |  K♦  |
| 10♦  |      |
Player 29, Dealer 14   

Note: The game stops
because the Player
"busts". Hitting on
19 was crazy!

Part 7 [Up to 100pts] - Name your source code file part7.cpp

A part 7 solution functions like a part 6 solution with the following modifications:

Sample run: red text represents user input
~/$ ./p7
choose deck> d55  
 Player Dealer
|  4♥  |  **  |
|  Q♥  |  5♥  |
Round 1 Player's turn
hit or stand? [h/s] h  
 Player Dealer
|  4♥  |  **  |
|  Q♥  |  5♥  |
|  5♦  |      |
Round 1 Dealer's turn
hit or stand? [h/s] h  
 Player Dealer
|  4♥  | 10♠  |
|  Q♥  |  5♥  |
|  5♦  |  7♦  |
Dealer busts, player wins

Sample run: red text represents user input
~/$ ./p7
choose deck> d58  
 Player Dealer
|  J♥  |  **  |
|  9♥  |  K♦  |
Round 1 Player's turn
hit or stand? [h/s] h  
 Player Dealer
|  J♥  |  4♥  |
|  9♥  |  K♦  |
| 10♦  |      |
Player busts, dealer wins

Sample run: red text represents user input
~/$ ./p7
choose deck> d88  
 Player Dealer
|  J♥  |  **  |
|  J♦  |  9♠  |
Round 1 Player's turn
hit or stand? [h/s] s  
 Player Dealer
|  J♥  |  **  |
|  J♦  |  9♠  |
Round 1 Dealer's turn
hit or stand? [h/s] s  
 Player Dealer
|  J♥  |  A♣  |
|  J♦  |  9♠  |
choose deck> d06  
 Player Dealer
|  6♠  |  **  |
|  2♦  |  A♣  |
Round 1 Player's turn
hit or stand? [h/s] s 
 Player Dealer
|  6♠  |  **  |
|  2♦  |  A♣  |
Round 1 Dealer's turn
hit or stand? [h/s] s  
 Player Dealer
|  6♠  |  K♥  |
|  2♦  |  A♣  |
Dealer wins 

Extra Credit [Up to 110pts] - Name your source code file partX.cpp

The extra credit solution will not even be considered unless the Part 7 Full credit solution functions correctly.

Your extra credit solution should play the game over and over again. Each time the player finishes a game, the program should ask whether the player wants to play again or quit. Each play the player must make a $5 bet. If the player wins, the player gets the bet plus some amount of winnings back. You may decide what the payouts are (could be as siumple getting your bet plus $5 back). You must report the players winnings / losses at the end of each round. The player must have the option of withdrawing from a game (not the table, just that game) after the initial two cards are dealt to player and dealer, but before any other play has taken place. Withdrawing means half the bet is returned to the player, but the other half goes to the house.


When to submit

Project 2 is due by COB on Monday, November 2nd, according to the course's particular definition of "COB". Late projects incurr a penalty of 3N points, where N is the number of days late. So, a project that is not turned in by COB Monday, 2 November, but which is turned in by COB Tuesday receives a 3 point penalty. A project that is not turned in by COB Tuesday, but which is turned in by COB Wednesday receives a 9 point penalty. And so on.

What to submit

You will submit the furthest properly functioning solution. So, if your Part 7 solution works, submit the Part 7 solution. If you don't have a properly functioning Part 7 solution, but your Part 6 solution works fine, submit a Part 6 solution. And so on. Note that what you submit must work, and absolutely must compile! What gets submitted is:
  1. Your source code (i.e the .cpp file). You will submit a printout of this (use codeprint) and an electronic copy (how to do the electronic submission will be explained later).
  2. A completed copy of this coversheet on paper.

How to submit

The paper portions of your submission should be stapled together and slid under your prof's door. Instructions on electronic submission: go to the directory with the project files and type:
submit proj02 part1.cpp part2.cpp part3.cpp part4.cpp part5.cpp part6.cpp part7.cpp partX.cpp

How projects are graded / how to maximize your points

Things to keep in mind to receive full marks:
  1. Submit all required items (as described above) on time.
  2. Make sure the form of your output matches the form of the example output in all ways. Of course the cards you see and decisions dealer and player make will vary from the examples you see.
  3. Make sure you follow the IC210 Style Guide. This means proper indentation, use of whitespace within lines of code, logical organization of chunks of code,
  4. Make sure you do a good job of putting things in functions. One monolithic main function is not OK, even if it works! The quality of your overall design will play a role, and a large part of that boils down to using functions well.
Most important: Look at the the grading sheet.