Created
July 2, 2012 20:47
-
-
Save thebinarypenguin/3035605 to your computer and use it in GitHub Desktop.
This is a solution to the extra credit project from EdgeCase's excellent Ruby Koans; it is an implementation of a dice game called greed. Greed is a "push your luck" style dice game for 2 or more players using 5 six-sided dice.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
class UI | |
def self.prompt_for_player_names | |
puts " _____ _____ ______ ______ _____ " | |
puts " / ____| | __ \\ | ____| | ____| | __ \\ " | |
puts " | | __ | |__) | | |__ | |__ | | | | " | |
puts " | | |_ | | _ / | __| | __| | | | | " | |
puts " | |__| | | | \\ \\ | |____ | |____ | |__| | " | |
puts " \\_____| |_| \\_\\ |______| |______| |_____/ " | |
puts | |
puts blue("Enter player names seperated by a comma ") | |
gets.chomp.strip.split(/\s*,\s*/) | |
end | |
def self.display_round_number(round_number) | |
puts | |
puts white("=== Round #{round_number} ==========================================================") | |
end | |
def self.display_last_round() | |
puts | |
puts white("=== Last Round =======================================================") | |
end | |
def self.display_player_name(player_name, in_the_game) | |
puts | |
puts yellow("> #{player_name}'s turn") | |
if !in_the_game | |
puts grey("(You must roll atleast #{Game::IN_GAME_POINTS} " + | |
"points in one turn to enter the game)") | |
end | |
end | |
def self.rolled_no_scoring_dice | |
puts | |
puts "You rolled " + red("no scoring dice") + ", your turn is over." | |
end | |
def self.rolled_all_scoring_dice(roll_points, turn_points, dice_remaining) | |
puts | |
puts "You rolled " + blue(roll_points) + " points giving you " + | |
"a total of " + blue(turn_points) + " points for this turn. " | |
puts "And you rolled " + green("all scoring dice") + " so you " + | |
"get to roll all #{dice_remaining} dice again." | |
print "Do you wish to roll again? " + grey("[y/n] ") | |
gets.chomp | |
end | |
def self.rolled_dice(roll_points, turn_points, dice_remaining) | |
puts | |
puts "You rolled " + blue(roll_points) + " points giving you " + | |
"a total of " + blue(turn_points) + " points for this turn." | |
print "You have " + blue(dice_remaining) + " dice remaining. " + | |
"Do you wish to roll again? " + grey("[y/n] ") | |
gets.chomp | |
end | |
def self.earned_points(turn_points, total_points) | |
puts | |
puts "You earned " + green(turn_points) + " points this turn " + | |
"giving you a total of " + green(total_points) + " points" | |
end | |
def self.display_final_scores(players) | |
puts | |
puts white("=== Final Scores =====================================================") | |
puts | |
players.each do |player| | |
puts " #{player.name}: " + green(player.total_points) | |
end | |
puts | |
end | |
def self.colorize(value, color) | |
case color | |
when :black then "\e[30m" + value.to_s + "\e[0m" | |
when :red then "\e[31m" + value.to_s + "\e[0m" | |
when :green then "\e[32m" + value.to_s + "\e[0m" | |
when :yellow then "\e[33m" + value.to_s + "\e[0m" | |
when :blue then "\e[34m" + value.to_s + "\e[0m" | |
when :magenta then "\e[35m" + value.to_s + "\e[0m" | |
when :cyan then "\e[36m" + value.to_s + "\e[0m" | |
when :white then "\e[37m" + value.to_s + "\e[0m" | |
when :bright_black then "\e[1m\e[30m" + value.to_s + "\e[0m" | |
when :bright_red then "\e[1m\e[31m" + value.to_s + "\e[0m" | |
when :bright_green then "\e[1m\e[32m" + value.to_s + "\e[0m" | |
when :bright_yellow then "\e[1m\e[33m" + value.to_s + "\e[0m" | |
when :bright_blue then "\e[1m\e[34m" + value.to_s + "\e[0m" | |
when :bright_magenta then "\e[1m\e[35m" + value.to_s + "\e[0m" | |
when :bright_cyan then "\e[1m\e[36m" + value.to_s + "\e[0m" | |
when :bright_white then "\e[1m\e[37m" + value.to_s + "\e[0m" | |
else value.to_s | |
end | |
end | |
def self.grey(text); colorize(text, :bright_black) end | |
def self.red(text); colorize(text, :bright_red) end | |
def self.green(text); colorize(text, :bright_green) end | |
def self.yellow(text); colorize(text, :bright_yellow) end | |
def self.blue(text); colorize(text, :bright_blue) end | |
def self.white(text); colorize(text, :bright_white) end | |
end | |
class DiceSet | |
attr_reader :total_dice | |
attr_reader :scoring_dice | |
attr_reader :non_scoring_dice | |
attr_reader :points | |
attr_reader :results | |
def initialize(num_dice) | |
@total_dice = num_dice | |
end | |
def roll | |
@scoring_dice = 0 | |
@non_scoring_dice = 0 | |
@points = 0 | |
@results = [] | |
# Get raw results | |
@total_dice.times { @results << rand(6) + 1 } | |
# Calculate score | |
1.upto(6) do |num| | |
qty = @results.count(num) | |
# Score triples | |
if qty >= 3 | |
@points += num == 1 ? 1000 : num * 100 | |
@scoring_dice += 3 | |
qty -= 3 | |
end | |
# Score single 1's | |
if num == 1 | |
@points += qty * 100 | |
@scoring_dice += qty | |
end | |
# Score single 5's | |
if num == 5 | |
@points += qty * 50 | |
@scoring_dice += qty | |
end | |
end | |
@non_scoring_dice = @total_dice - @scoring_dice | |
@results | |
end | |
def no_scoring_dice? | |
@scoring_dice == 0 ? true : false | |
end | |
def all_scoring_dice? | |
@scoring_dice == @total_dice ? true : false | |
end | |
end | |
class Player | |
attr_reader :name | |
attr_reader :finished | |
attr_reader :total_points | |
def initialize(name) | |
@name = name | |
@in_the_game = false | |
@finished = false | |
@total_points = 0 | |
end | |
def take_turn | |
roll_points = 0 | |
turn_points = 0 | |
dice_remaining = Game::DICE_TO_USE | |
UI.display_player_name(@name, @in_the_game) | |
loop do | |
# Roll dice | |
dice = DiceSet.new(dice_remaining) | |
dice.roll | |
roll_points = dice.points | |
turn_points += roll_points | |
# Check results | |
if dice.no_scoring_dice? | |
UI.rolled_no_scoring_dice | |
break | |
elsif dice.all_scoring_dice? | |
dice_remaining = Game::DICE_TO_USE | |
answer = UI.rolled_all_scoring_dice(roll_points, turn_points, dice_remaining) | |
else | |
dice_remaining = dice.non_scoring_dice | |
answer = UI.rolled_dice(roll_points, turn_points, dice_remaining) | |
end | |
if answer.downcase == "n" | |
if !@in_the_game | |
if turn_points < Game::IN_GAME_POINTS | |
turn_points = 0 | |
else | |
@in_the_game = true; | |
end | |
end | |
@total_points += turn_points | |
if @total_points >= Game::END_GAME_POINTS | |
@finished = true | |
end | |
UI.earned_points(turn_points, @total_points) | |
break | |
end | |
end | |
end | |
end | |
class Game | |
DICE_TO_USE = 5 | |
IN_GAME_POINTS = 300 | |
END_GAME_POINTS = 3000 | |
def initialize | |
@players = [] | |
@round = 1 | |
@last_round = false | |
start_game | |
end | |
def start_game | |
UI.prompt_for_player_names.each do |name| | |
@players << Player.new(name) | |
end | |
# Play normal rounds until a player accumulates END_GAME_POINTS | |
# That player is now the one to beat. | |
until @last_round | |
UI.display_round_number(@round) | |
@players.each do |player| | |
player.take_turn | |
if player.finished | |
@last_round = true | |
break | |
end | |
end | |
@round += 1 | |
end | |
# Play last round. Give every other player one turn to try and | |
# beat the high score | |
if @last_round | |
UI.display_last_round() | |
@players.each do |player| | |
unless player.finished | |
player.take_turn | |
end | |
end | |
end | |
UI.display_final_scores(@players) | |
end | |
end | |
# Play Game | |
Game.new |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment