DEV Community

dev.to staff
dev.to staff

Posted on

Daily Challenge #41 - Greed is Good

Greed is a dice game played with five six-sided dice. Using an array containing five six-sided dice values, write a function that will score a throw according to the following rules:

Three 1's => 1000 points
Three 6's => 600 points
Three 5's => 500 points
Three 4's => 400 points
Three 3's => 300 points
Three 2's => 200 points
One 1 => 100 points
One 5 => 50 point

A single die can only be counted once in each roll. For example, a "5" can only count as part of a triplet (contributing to the 500 points) or alone (as 50 points), but not both in the same roll.

Example Scoring

5 1 3 4 1 => 50 + 2 * 100 = 250
1 1 1 3 1 => 1000 + 100 = 1100
2 4 4 5 4 => 400 + 50 = 450

You can try to fill the array with random values. If you have extra time, you can also try to keep track of the player's score over several throws.


This challenge comes from user JulianNicholls. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge for a future post? Email yo+challenge@dev.to with your suggestions!

Top comments (18)

Collapse
 
danielsclet profile image
Daniel Santos • Edited

its pretty? no... but it works

function GG(arr) { let map = [], result = 0; arr.join("").split("").forEach(el => map[el] = (map[el] || 0) + 1); for (let index = 0; index <= 6; index++) { if (map[index] != undefined) { switch (index) { case 1: if (map[index] >= 3) { result += 1000; if ((map[index] - 3) > 0) result += (map[index] - 3) * 100; } else { result += map[index] * 100 } break; case 2: if (map[index] >= 3) result += 200; break; case 3: if (map[index] >= 3) result * 300; break; case 4: if (map[index] >= 3) result += 400; break; case 5: if (map[index] >= 3) { result += 500; if ((map[index] - 3) > 0) result += (map[index] - 3) * 50; } else { result += map[index] * 50 } break; case 6: if (map[index] >= 3) result += 600; break; } } } return result; } GG([5, 1, 3, 4, 1]) // 250 GG([1, 1, 1, 3, 1]) // 1100 GG([2, 4, 4, 5, 4]) // 450 
Collapse
 
hoffmann profile image
Peter Hoffmann

Very understandable and faster! 👍

Collapse
 
danielsclet profile image
Daniel Santos

Thanks Peter 😃

Collapse
 
jacoby profile image
Dave Jacoby

Perl

#!/usr/bin/env perl use strict; use warnings; use utf8; use feature qw{ say signatures }; no warnings qw{ experimental::signatures }; my @roll = map { d6() } 1 .. 5; say join ' ', @roll; say score(@roll); sub score (@roll) { my $score = 0; my $count; map { $count->{$_} = 0 } 1 .. 6; for my $d (@roll) { $count->{$d}++; } if ( $count->{1} >= 3 ) { $score += 1000; $count->{1} -= 3 } if ( $count->{2} >= 3 ) { $score += 200; $count->{2} -= 3 } if ( $count->{3} >= 3 ) { $score += 300; $count->{3} -= 3 } if ( $count->{4} >= 3 ) { $score += 400; $count->{4} -= 3 } if ( $count->{5} >= 3 ) { $score += 500; $count->{5} -= 3 } if ( $count->{6} >= 3 ) { $score += 600; $count->{6} -= 3 } while ( $count->{1} > 0 ) { $score += 100; $count->{1}-- } while ( $count->{5} > 0 ) { $score += 50; $count->{5}-- } return $score; } sub d6 { return 1 + int rand 6; } 
Collapse
 
hanachin profile image
Seiei Miyagi

ruby <3

def score(values) values.tally.sum do |n, cnt, acc = 0| case [n, cnt] in 1, 3.. then cnt -= 3 acc += 1000 redo in 6, 3.. then cnt -= 3 acc += 600 redo in 5, 3.. then cnt -= 3 acc += 500 redo in 4, 3.. then cnt -= 3 acc += 400 redo in 3, 3.. then cnt -= 3 acc += 300 redo in 2, 3.. then cnt -= 3 acc += 200 redo in 1, 1.. then cnt -= 1 acc += 100 redo in 5, 1.. then cnt -= 1 acc += 50 redo else acc end end end p score([5, 1, 3, 4, 1]) # => 50 + 2 * 100 = 250 p score([1, 1, 1, 3, 1]) # => 1000 + 100 = 1100 p score([2, 4, 4, 5, 4]) # => 400 + 50 = 450 
Collapse
 
alvaromontoro profile image
Alvaro Montoro

JavaScript

const greedy = arr => { let points = 0; const dices = { 1:0, 2:0, 3:0, 4:0, 5:0, 6:0 }; arr.forEach(el => dices[el]++); Object.keys(dices).forEach(key => { if (dices[key] >= 3) { points += key * (key == 1 ? 1000 : 100); if (key == 1) points += (dices[key] - 3) * 100; if (key == 5) points += (dices[key] - 3) * 50; } else { if (key == 1) points += dices[key] * 100; if (key == 5) points += dices[key] * 50; } }) return points; } 

Live demo on CodePen.

Collapse
 
willsmart profile image
willsmart

JS implementation keeping the rules as data

function score( dice ) { // Business rules of the game: // v: the dice value // c: the number of dice required to trigger the rule // p: the points added each time the rule is triggered const scoringRules = [ {v: 1, c: 3, p: 1000}, {v: 6, c: 3, p: 600}, {v: 5, c: 3, p: 500}, {v: 4, c: 3, p: 400}, {v: 3, c: 3, p: 300}, {v: 2, c: 3, p: 200}, {v: 1, c: 1, p: 100}, {v: 5, c: 1, p: 50} ] // returns the score given a histogram mapping a dice value to the number of dice with that value const scoreForHistogram = counts => { let score = 0 for (const {v, c, p} of scoringRules) { const ruleCount = Math.floor((counts[v] || 0) / c); counts[v] -= ruleCount * c; score += ruleCount * p; } return score; }; // Generate the histogram required by scoreForHistogram const counts = [...Array(7)].map(v=>0);// note that the rest of the logic uses 1-indexed arrays, so we need 7 entries to get a valid counts[6] entry for (const v of dice) counts[v]++; return scoreForHistogram(counts) } 
Collapse
 
itsdarrylnorris profile image
Darryl Norris

Keep the rules as data is the way to go. 🔥🔥🔥

Collapse
 
thepeoplesbourgeois profile image
Josh • Edited

Easy peasy, lemon squeezy

(language: Elixir)

defmodule Greed do def score_dice([_|_] = dice) do tally(dice) |> score end defp tally(enumerable) do Enum.reduce(enumerable, %{}, fn item, tally -> count = tally[item] || 0 put_in(tally[item], count+1) end) end defp score(tally, total \\ 0) defp score(%{1 => dice} = tally, total) when dice >= 3, do: score(%{tally | 1 => dice - 3}, total + 1000) defp score(%{1 => dice} = tally, total) when dice >= 1, do: score(%{tally | 1 => dice - 1}, total + 100) defp score(%{2 => dice} = tally, total) when dice >= 3, do: score(%{tally | 2 => dice - 3}, total + 200) defp score(%{3 => dice} = tally, total) when dice >= 3, do: score(%{tally | 3 => dice - 3}, total + 300) defp score(%{4 => dice} = tally, total) when dice >= 3, do: score(%{tally | 4 => dice - 3}, total + 400) defp score(%{5 => dice} = tally, total) when dice >= 3, do: score(%{tally | 5 => dice - 3}, total + 500) defp score(%{5 => dice} = tally, total) when dice >= 1, do: score(%{tally | 5 => dice - 1}, total + 50) defp score(%{6 => dice} = tally, total) when dice >= 3, do: score(%{tally | 6 => dice - 3}, total + 600) defp score(_totaled_tally, score), do: score end Greed.score_dice([1,1,1,1,1]) # 1200 Greed.score_dice([1,1,1,1,3]) # 1100 Greed.score_dice([1,1,1,3,3]) # 1000 Greed.score_dice([1,3,1,3,3]) # 500 Greed.score_dice([1,3,5,3,3]) # 450 
Collapse
 
geraldhost profile image
Gerald Host

A super gross unreadable solution but fun none the less 😂

def score(inp): def single_score(n, c): return (n * (100 if n != 1 else 1000) if c >= 3 and n in t else 0) + ((n * (10 if n != 1 else 100)) * (c - (3 if c >= 3 else 0)) if n in s else 0) return sum([single_score(n, c) for n, c in {i: inp.count(i) for i in inp}.items()]) score([2, 4, 4, 5, 4]) # 450 
Collapse
 
peter279k profile image
peter279k

Here is my simple solution with Python:

def score(dice): dice_count = [0, 0, 0, 0, 0, 0] sum = 0 for point in dice: dice_count[point-1] += 1 while dice_count[0] >= 3: sum += 1000 dice_count[0] -= 3 if dice_count[0] <= 2 and dice_count != 0: sum += 100 * dice_count[0] if dice_count[1] >= 3: sum += 200 else: sum += 0 if dice_count[2] >= 3: sum += 300 else: sum += 0 if dice_count[3] >= 3: sum += 400 else: sum += 0 while dice_count[4] >= 3: sum += 500 dice_count[4] -= 3 if dice_count[4] <= 2 and dice_count[4] != 0: sum += 50 * dice_count[4] if dice_count[5] >= 3: sum += 600 else: sum += 0 return sum 
Collapse
 
matrossuch profile image
Mat-R-Such

Python

import random def pounts(p): if p == 1: return 1000 else: return p*100 def greed(): d=sorted(random.choices(range(1,7),k=5)) print(d) dice = 1 p = 0 while len(d) > 0: if d.count(dice) >= 3: p += pounts(dice) del d[:4] elif (d[0] == 1 or d[0] == 5) and (dice == 5 or dice == 1): if d.count(1) == 2 or d.count(5) == 2: p += int(100 if d[0] == 1 else 50) * 2 del d[:2] else: p += int(100 if d[0] == 1 else 50) d.pop(0) dice += 1 else: if d[0] == dice and d.count(dice) == 1: d.pop(0) elif d[0] == dice and d.count(dice) == 2: del d[:2] dice += 1 return p 
Collapse
 
jacksoncds profile image
Jackson DaSilva

C#

Repl.it

using System; using System.Linq; using System.Threading; class MainClass { public static void Main (string[] args) { try { var greed = new Greed(); greed.Throw(); while (true) { Thread.Sleep(5); greed.Throw(); } } catch(Exception) { Console.WriteLine("\nYou win!, game over."); } } } class Greed { public int Score = 0; public int Throws = 0; public double GetAveragePerThrow(){ if(this.Throws == 0){ return 0; } return this.Score / this.Throws; } public int Roll(Random random){ var rolled = random.Next(1, 7); Console.Write(rolled); return rolled; } public int GetScore(int[] rolls){ var score = 0; var one = rolls.Count(c => c == 1); var two = rolls.Count(c => c == 2); var three = rolls.Count(c => c == 3); var four = rolls.Count(c => c == 4); var five = rolls.Count(c => c == 5); var six = rolls.Count(c => c == 6); if(one == 1){ score += 100; } if(one == 3){ score += 1000; } if(two == 3){ score += 200; } if(three == 3){ score += 300; } if(four == 3){ score += 400; } if(five == 1){ score += 50; } if(five == 3){ score += 500; } if(six == 3){ score += 600; } if(one == 5){ throw new Exception("You win."); } return score; } public int[] Throw(){ var rollsPerThrow = 5; var rolls = new int[rollsPerThrow]; var random = new Random(); Console.WriteLine("Rolls:"); for(var i = 0; i < rollsPerThrow; i++){ rolls[i] = this.Roll(random); } var rollScore = this.GetScore(rolls); this.Throws++; this.Score += rollScore; Console.WriteLine($"\nScore: \n{rollScore}"); Console.WriteLine($"Total score: {this.Score} - Throws: {this.Throws} - Average score per throw: {this.GetAveragePerThrow()}"); return rolls; } }