#!/bin/bash

initializer()
{
    #Make sure number of players is a number.
    if ! [[ $1 =~ ^[1-9]+$ ]] ; then
        echo "Usage: yahtzee or yahtzee number of players."
    fi
    #creates the initial player variables for all the players
    genIndex=1
    while [ $genIndex -le $1 ] ; do
        player[$genIndex]="false"
        i=0
        while [ $i -lt 12 ] ; do
            player[$genIndex]="${player[$genIndex]}:false"
            let i++
        done
        let genIndex++
    done
    #Randomly pick which player goes first.
    if [ $1 -gt 1 ] ; then
        playerIndex=$(rolldice 1d$1 | tr -d "[:space:]")
    else
        playerIndex=1
    fi
}

roll()
{
    clear
    unset diceSoundString
    #Only play the number of dice rolls we are actually rolling.
    i=0
    while [ $i -lt $1 ] ; do
        diceSoundString="$diceSoundString sounds/die$(rolldice 1d2 | tr -d "[:space:]").ogg"
        let i++
    done
    #if there is only one die the -m (mix) option is not needed.
    if [ $i -eq 1 ] ; then
        play -qV0 $diceSoundString remix v0.$(rolldice 1d4+4) v0.$(rolldice 1d4+4)
    else
        play -mqV0 $diceSoundString remix v0.$(rolldice 1d4+4) v0.$(rolldice 1d4+4)
    fi
    echo "Player $playerIndex rolls $1 $(if [ $1 -gt 1 ] ; then echo "dice";else echo "die";fi)."
    #if 5 dice are needed then replace the whole dice variable, if not, only replace the rolled dice.
    if [  $1 -lt 5 ] ;then
        dice="$dice $(rolldice ${1}x6 | tr -s " ")"
    else
        dice="$(rolldice 5x6 | tr -s " ")"
    fi
    #remove extra spaces from the dice string.
    dice="$(echo "$dice" | tr -s "[:space:]")"
    #Only show the rolled dice.
    echo "${dice:$((${#dice} - $1 * 2)):${#dice}}." | rev | sed -e 's/^. /./' -e 's/ / ,/g' -e 's/ ,/ dna /' | rev
}

score_sheet()
{
    display="true"
    double="false"
    tripple="false"
    #Initialize the score sheet to all 0s.
    i=1
    while [ $i -le 13 ] ; do
        score[$i]=0
        let i++
    done
    #Draw upper line of score sheet.
    line=1
    echo -n "|"
    while [ $line -lt 29 ] ; do
        echo -n "-"
        let line++
    done
    echo "|"
    #dice total is needed for scoring chance, small straight and large straight.
    diceTotal="$(echo "$dice" | sed -e 's/^ //' -e 's/ $//' | tr " " "+")"
    diceTotal=$(($diceTotal))
    #set the chance section.
    score[9]=$diceTotal
    #Check for straights.
    straight=$(echo "$dice" | tr " " "\n" | sort | tr -d "\n" | tr -s "[:digit:]")
    if [ $straight -eq 1234 -o $straight -eq 2345 -o $straight -eq 3456 ] ; then
        #We have a small straight.
        score[12]=30
    fi
    if [ $straight -eq 12345 -o $straight -eq 23456 ] ; then
        #We have a large straight, which automatically means we have a small straight as well.
        score[11]=40
        score[12]=30
    fi
    #check how many of each die there is.
    i=1
    while [ $i -le 13 ] ; do
        x="$(echo "$dice" | grep $i | tr -Cd "$i " | tr -s " " | sed -e 's/^ //' -e 's/ $//' | tr " " "+")"
        #Check for yahtzee
        if [ "$x" = "${i}+${i}+${i}+${i}+${i}" ] ; then
            if [[ "$(echo "${player[$1]}" | cut -d ":" -f 13)" == "50" ]] ; then
                #More than 1 yahtzee is 100 points.
                score[13]=100
            else
                #First yahtzee is 50 points.
                score[13]=50
            fi
        fi
    #set the dice score for each set of pips.
    if [ "$x" != "" ] ; then
        score[$i]=$(($x))
    fi
    #First part of check for full house, 2 of a kind + 3 of a kind.
    if [ $((2 * $i)) -eq ${score[$i]} ] ; then
        double="true"
        if [ "$tripple" == "true" ] ; then
            score[10]=25
        fi
    fi
    #check for 3 of a kind as well as the second check for full house.
    if [ $((3 * $i)) -eq ${score[$i]} ] ; then
        tripple="true"
        if [ "$double" == "true" ] ; then
            score[10]=25
        fi
        score[7]=$diceTotal
    fi
    #Check for 4 of a kind, which automatically means there is 3 of a kind too.
    if [ $((4 * $i)) -eq ${score[$i]} ] ; then
        score[7]=$diceTotal
        score[8]=$diceTotal
    fi
    case $i in
        7)
        #Draw section seperation line in score sheet.
        line=1
        echo -n "|"
        while [ $line -lt 29 ] ; do
            echo -n "-"
            let line++
        done
        echo "|"
        #Only display the option if it has not already been scored.
        if [[ "$(echo "${player[$1]}" | cut -f $i -d ":")" == "false" ]] ; then
            echo -n "|    3 of a kind         "
            display="true"
        else
            display="false"
        fi
        ;;
        8)
        if [[ "$(echo "${player[$1]}" | cut -f $i -d ":")" == "false" ]] ; then
            echo -n "|    4 of a kind         "
            display="true"
        else
            display="false"
        fi
        ;;
        9)
        if [[ "$(echo "${player[$1]}" | cut -f $i -d ":")" == "false" ]] ; then
            echo -n "|    Chance              "
            display="true"
        else
            display="false"
        fi
        ;;
        10)
        if [[ "$(echo "${player[$1]}" | cut -f $i -d ":")" == "false" ]] ; then
            echo -n "|    Full house          "
            display="true"
        else
            display="false"
        fi
        ;;
        11)
        if [[ "$(echo "${player[$1]}" | cut -f $i -d ":")" == "false" ]] ; then
            echo -n "|    Large straight      "
            display="true"
        else
            display="false"
        fi
        ;;
        12)
        if [[ "$(echo "${player[$1]}" | cut -f $i -d ":")" == "false" ]] ; then
            echo -n "|    Small straight      "
            display="true"
        else
            display="false"
        fi
        ;;
        13)
        if [[ "$(echo "${player[$1]}" | cut -f $i -d ":")" != "0" ]] ; then
            echo -n "|    Yahtzee             "
            display="true"
        else
            display="false"
        fi
        ;;
        *)
        if [[ "$(echo "${player[$1]}" | cut -f $i -d ":")" == "false" ]] ; then
            echo -n "|    ${i}s               "
            display="true"
        else
            display="false"
        fi
    esac
    #Only display the score if the first half is displayed.
    if [ "$display" == "true" ] ; then
        #Format the score so the right side of the box lines up.
        if [ ${score[$i]} -lt 10 ] ; then
            echo "${score[$i]}   |"
        elif [ ${score[$i]} -ge 100 ] ; then
            echo "${score[$i]} |"
        else
            echo "${score[$i]}  |"
        fi
    fi
    let i++
    done
    #Draw the bottom of the score sheet.
    line=1
    echo -n "|"
    while [ $line -lt 29 ] ; do
        echo -n "_"
        let line++
    done
    echo "|"
}

dice_parser()
{
    error="true"
    while [ "$error" == "true" ] ; do
        #Remove spaces from the reroll string.
        continue="$(echo "$continue" | tr -d "[:space:]")"
        #Make sure the reroll string contains valid dice options.
        if ! [[ "$continue" =~ ^[1-6]+$ ]] ; then
            error="true"
            echo -n "Dice must be numbers 1-6 only. "
        else
            error="false"
        fi
        #Make sure the requested dice are actually available to reroll.
        if [[ $(echo "$dice" | tr -d "$continue") == "$dice" ]] ; then
            if [ "$error" == "false" ] ; then
                error="true"
                unset continue
                echo -n "That is not one of the available dice to reroll. "
            fi
        else
            error="false"
        fi
        #Only oporate on the dice string if there are no errors.
        if [ "$error" == "false" ] ; then
            i=0
            while [ $i -lt ${#continue} ] ; do
                #Remove all the selected dice from the dice string.
                dice=$(echo "$dice" | sed "s/${continue:$i:1} //")
                let i++
            done
        else
            #Play error sound.
            play -qV0 "|sox -n -p synth saw E2 fade 0 0.25 0.05" "|sox -n -p synth saw E2 fade 0 0.25 0.05" norm -7
        fi
        #Set the number of dice that need to be rerolled.
        dieCounter=$((5 - ${#dice} / 2))
        if [ "$error" == "true" ] ; then
            read continue
        fi
    done
}

score_dice()
{
    error="true"
    while [ "$error" == "true" ] ; do
        read -n 1 -p "Select score slot. " continue
        case "${continue^}" in
        [1-6])
            #scoring for slots 1-6.
            fieldIndex=$continue
        ;;
        #3 of a kind.
        "#")
            fieldIndex=7
        ;;
        #4 of a kind.
        "$")
            fieldIndex=8
        ;;
        #Chance.
        "C")
            fieldIndex=9
        ;;
        #Full house.
        "F")
            fieldIndex=10
        ;;
        #Large straight.
        "L")
            fieldIndex=11
        ;;
        #Small straight.
        "S")
            fieldIndex=12
        ;;
        #Yahtzee
        "Y")
            fieldIndex=13
        ;;
        *)
            unset fieldIndex
        esac
        #Make sure the key press was valid.
        if [ "$fieldIndex" != "" ] ; then
            #make sure the selected slot hasn't already been scored.
            if [[ $(echo "${player[$1]}" | cut -d ":" -f $fieldIndex) != "false" ]] ; then
                play -qV0 "|sox -n -p synth saw E2 fade 0 0.25 0.05" "|sox -n -p synth saw E2 fade 0 0.25 0.05" norm -7
                error="true"
                echo -e "\nThat is not a valid scoring option."
            else
                error="false"
            fi
        else
            error="true"
        fi
    done
    #Set the score in the player variable.
    player[$1]="$(echo "${player[$1]}" | sed 's/:/\n/g' | sed -e $fieldIndex"s/false/${score[$fieldIndex]}/" | tr "\n" ":" | sed 's/:$//')"
    playerScore="$(echo "${player[$1]}" | tr -d "[:alpha:]" | tr -s ":" | tr ":" "+" | sed -e 's/^\+//' -e 's/\+$//')"
    echo
    read -t 3 -n 1 -p "Player $1's score is $(($playerScore))." continue
}

if [ $# -eq 1 ] ; then
    initializer $1
    totalPlayers="$1"
else
    initializer 1
    totalPlayers=1
fi
#If the word false is in any player varaible the game is not over.
while [[ $(echo "${player[@]}" | grep "false") ]] ; do
    rollCounter=0
    dieCounter=5
    continue="true"
    #Each player gets up to 3 rolls.
    while [ $rollCounter -lt 3 ] ; do
        if [ "$continue" != "" ] ; then
            roll $dieCounter
        else
            break
        fi
        #show the score sheet after each roll.
        score_sheet $playerIndex
        let rollCounter++
        if [ $rollCounter -lt 3 ] ; then
            read -p "Enter the dice you would like to reroll or enter to keep all the dice." continue
            if [ "$continue" != "" ] ; then
                dice_parser $playerIndex
            fi
        fi
    done
    score_dice $playerIndex
if [ $playerIndex -ge $totalPlayers ] ; then
    playerIndex=1
else
    let playerIndex++
fi
done
#show who won the game.
i=1
winningScore=0
winner=1
while [ $i -le $totalPlayers ] ; do
    playerScore="$(echo "${player[$i]}" | tr -d "[:alpha:]" | tr -s ":" | tr ":" "+" | sed -e 's/^\+//' -e 's/\+$//')"
    playerScore=$(($playerScore))
    if [ $playerScore -gt $winningScore ] ; then
        winningScore=$playerScore
        winner=$i
    fi
    let i++
done
echo
echo "Player $winner wins!!!"
exit 0
