// yahtzee.cpp
#include <iostream>
#include <stdlib.h>
using namespace std;
const int NUM_DICE = 5;
// Retun sum of all dice
int sumOfAll(int dice[NUM_DICE])
{
int sum = 0;
for(int i = 0; i < NUM_DICE; i++) {
sum += dice[i];
}
return sum;
}
// If there are three dice with the same value, return the sum
// of the values of all dice, else return zero.
int threeOfAKind(int dice[NUM_DICE])
{
int tally[7] = { 0 };
for(int i = 0; i < NUM_DICE; i++) {
tally[dice[i]]++;
if(tally[dice[i]] == 3) return sumOfAll(dice);
}
return 0;
}
// If there are four dice with the same value, return the sum
// of the values of all dice, else return zero.
int fourOfAKind(int dice[NUM_DICE])
{
int tally[7] = { 0 };
for(int i = 0; i < NUM_DICE; i++) {
tally[dice[i]]++;
if(tally[dice[i]] == 4) return sumOfAll(dice);
}
return 0;
}
// If there are three dice with the same value, return 50,
// else return zero.
int fiveOfAKind(int dice[NUM_DICE])
{
int tally[7] = { 0 };
for(int i = 0; i < NUM_DICE; i++) {
tally[dice[i]]++;
if(tally[dice[i]] == 5) return 50;
}
return 0;
}
// If there are three dice with the same value AND two dice with the
// same (but different) value, return 25, else return zero.
int fullHouse(int dice[NUM_DICE])
{
bool three = false, two = false;
int tally[7] = { 0 };
for(int i = 0; i < NUM_DICE; i++) {
tally[dice[i]]++;
}
for(int i = 1; i <= 6; i++) {
if(tally[i] == 3) {
three = true;
}
if(tally[i] == 2) {
two = true;
}
}
if(two && three) {
return 25;
}
return 0;
}
// If there is a sequence of four dice (1234, 2345, or 3456), return
// 30, else return zero.
int smallStraight(int dice[NUM_DICE])
{
int tally[7] = { 0 };
for(int i = 0; i < NUM_DICE; i++) {
tally[dice[i]]++;
}
for(int start = 1; start <= 3; start++) {
int n = 0;
for(int k = 0; k < 4; k++) {
if(tally[start+k] > 0) {
n++;
}
}
if(n >= 4) return 30;
}
return 0;
}
// If there is a sequence of five dice (12345 or 23456), return 40,
// else return zero.
int largeStraight(int dice[NUM_DICE])
{
int tally[7] = { 0 };
for(int i = 0; i < NUM_DICE; i++) {
tally[dice[i]]++;
if(tally[dice[i]] > 1) return 0;
}
if(tally[1] == 0 || tally[6] == 0) {
return 40;
}
return 0;
}
// Return the sum of the dice that have the given value. So, if value
// is 4, then the sum of all dice whose value is four.
int sumOfValue(int dice[NUM_DICE], int value)
{
int sum = 0;
for(int i = 0; i < NUM_DICE; i++) {
if(dice[i] == value) {
sum += value;
}
}
return sum;
}
void rollDice(int dice[NUM_DICE])
{
for(int i = 0; i < NUM_DICE; i++) {
dice[i] = rand()%6+1;
}
}
void showDice(int dice[NUM_DICE])
{
cout << "Your dice: ";
for(int i = 0; i < NUM_DICE; i++) {
cout << dice[i] << " ";
}
cout << "\n";
cout << " ";
for(int i = 0; i < NUM_DICE; i++) {
cout << (char)('a' + i) << " ";
}
cout << "\n";
}
void testCase(string name, int dice[NUM_DICE], int score, int expected)
{
cout << name << ": ";
for(int i = 0; i < NUM_DICE; i++) {
cout << dice[i] << " ";
}
cout << "-> " << score;
if(score == expected) {
cout << " PASS\n";
}
else {
cout << " FAIL, expected " << expected << "\n";
}
}
void testCases()
{
int dice[NUM_DICE];
// Test "N of a kind"
dice[0] = dice[1] = dice[2] = dice[3] = dice[4] = 3;
testCase("fiveOfAKind", dice, fiveOfAKind(dice), 50);
dice[2] = 4;
testCase("fiveOfAKind", dice, fiveOfAKind(dice), 0);
testCase("fourOfAKind", dice, fourOfAKind(dice), 3*4+4);
dice[0] = 2;
testCase("fourOfAKind", dice, fourOfAKind(dice), 0);
testCase("threeOfAKind", dice, threeOfAKind(dice), 3*3+2+4);
dice[1] = 5;
testCase("threeOfAKind", dice, threeOfAKind(dice), 0);
// Test full house
dice[0] = dice[2] = 6;
dice[1] = dice[3] = dice[4] = 5;
testCase("fullHouse", dice, fullHouse(dice), 25);
dice[0] = dice[3] = 1;
dice[1] = dice[2] = dice[4] = 2;
testCase("fullHouse", dice, fullHouse(dice), 25);
testCase("ones", dice, sumOfValue(dice, 1), 2);
testCase("twos", dice, sumOfValue(dice, 2), 6);
testCase("threes", dice, sumOfValue(dice, 3), 0);
// Straights
dice[0] = 1;
dice[2] = 2;
dice[1] = 3;
dice[4] = 4;
dice[3] = 5;
testCase("largeStraight", dice, largeStraight(dice), 40);
dice[0] = 6;
testCase("smallStraight", dice, smallStraight(dice), 30);
testCase("largeStraight", dice, largeStraight(dice), 40);
dice[0] = 2;
testCase("smallStraight", dice, smallStraight(dice), 30);
testCase("largeStraight", dice, largeStraight(dice), 0);
dice[4] = 5;
testCase("smallStraight", dice, smallStraight(dice), 0);
testCase("largeStraight", dice, largeStraight(dice), 0);
dice[0] = 1;
dice[1] = 2;
dice[2] = 3;
dice[3] = 4;
dice[4] = dice[5] = 4;
testCase("smallStraight", dice, smallStraight(dice), 30);
dice[0] = 3;
dice[1] = 4;
dice[2] = 5;
dice[3] = 6;
dice[4] = dice[5] = 4;
testCase("smallStraight", dice, smallStraight(dice), 30);
}
void play()
{
srand(time(NULL)); // Initialize random number generator
int dice[NUM_DICE];
rollDice(dice);
showDice(dice);
cout << "What to reroll? ";
string reroll;
getline(cin, reroll);
for(int i = 0; i < reroll.size(); i++) {
int choice = reroll[i] - 'a';
cout << "Will reroll " << choice << "\n";
dice[choice] = rand()%6+1;
}
showDice(dice);
int ones = sumOfValue(dice, 1);
int twos = sumOfValue(dice, 2);
cout << "a. Ones: " << ones << "\n";
cout << "b. Twos: " << twos << "\n";
int threeK = threeOfAKind(dice);
if(threeK > 0) {
cout << "c. Three of a kind: " << threeK << "\n";
}
int fourK = fourOfAKind(dice);
if(fourK > 0) {
cout << "d. Four of a kind: " << fourK << "\n";
}
int fiveK = fiveOfAKind(dice);
if(fiveK > 0) {
cout << "e. Yahtzee: " << fiveK << "\n";
}
cout << "Score as which? ";
string scoreChoice;
getline(cin, scoreChoice);
cout << "Thanks for playing.\n";
}
int main()
{
//play();
testCases();
return 0;
}