diff --git a/dice.go b/dice.go index 0a7f7c2..cbffbc1 100644 --- a/dice.go +++ b/dice.go @@ -118,9 +118,58 @@ func validateDice(input string, dice []string) (Roll, error) { return wellFormedDice, nil } -func flipCoin() string { - coin := []string{"Heads", "Tails"} - side := coin[rand.Intn(len(coin))] +func flipCoin(input string) string { + coinCount, err := parseCoinCount(input) + if err != nil { + return err.Error() + } + + flips := make([]int, coinCount) + for i := 0; i < coinCount; i++ { + flips[i] = rand.Intn(2) + } + return formatFlips(flips, coinCount) +} + +func parseCoinCount(input string) (int, error) { + coinMaximum := 50 + + coins := coinRegex.FindStringSubmatch(input) + if coins[1] == "" { + // no number specified - implicit one flip + return 1, nil + } + + numCoins, err := strconv.Atoi(coins[1]) + if err != nil { + return 0, errors.New("malformed coin toss") + } - return fmt.Sprintf("%s.", side) + if numCoins > coinMaximum { + return 0, errors.New("malformed coin toss (max count is 50)") + } + if numCoins < 1 { + return 0, errors.New("malformed coin toss (min count is 1)") + } + return numCoins, nil } + +func formatFlips(flips []int, count int) string { + prefix := "" + coinNames := []string{"Heads", "Tails"} + joiner := ", " + if count > 5 { + prefix = fmt.Sprintf("%d coins: ", count) + coinNames = []string{"H", "T"} + joiner = "" + } + + formatted := make([]string, len(flips)) + for i := 0; i < len(formatted); i++ { + formatted[i] = coinNames[flips[i]] + } + + return fmt.Sprintf("%s%s.", prefix, strings.Join(formatted, joiner)) +} + + diff --git a/dice_test.go b/dice_test.go index 902b16b..2f4ba26 100644 --- a/dice_test.go +++ b/dice_test.go @@ -8,7 +8,7 @@ import ( func TestFlipCoin(t *testing.T) { for i := 1; i < 10; i++ { - result := flipCoin() + result := flipCoin("coin") validOutput := regexp.MustCompile(`(?:Heads|Tails).`) if !(validOutput.MatchString(result)) { t.Errorf(`FAIL: Expected heads or tails in output, but result was \"%s\"`, result) diff --git a/main.go b/main.go index cbfea29..cb8ec93 100644 --- a/main.go +++ b/main.go @@ -434,9 +434,9 @@ func handleCommand(params *fryatogParams, c chan string) { c <- rollDice(message) return - case message == "coin": + case coinRegex.MatchString(message): log.Debug("Coin flip") - c <- flipCoin() + c <- flipCoin(message) return case ruleRegexp.MatchString(message), diff --git a/utils.go b/utils.go index 62196cb..9571101 100644 --- a/utils.go +++ b/utils.go @@ -28,6 +28,7 @@ var ( wordStartingWithBang = regexp.MustCompile(`\s+! *\S+`) diceRegex = regexp.MustCompile(`^(?:roll )?\s*(.*?)d(\d+)([+-]\d+)?`) + coinRegex = regexp.MustCompile(`^coin(?:\s+(\d+))?`) cardMetadataRegex = regexp.MustCompile(`(?i)^(?:rulings?|reminder|flavou?r) `)