Notes from 12/5

yahtzee.cpp

// 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;
}