#!/usr/bin/env ruby module Term CSI = "[" def sgr(*code) "#{CSI}#{code.join(?;)}m" end module_function :sgr RESET = sgr(0) BOLD = sgr(1, 97) RED = sgr(31) GREEN = sgr(32) YELLOW = sgr(33) BLUE = sgr(34) PURPLE = sgr(35) end class Roll def initialize(res, cuts) @res = res @cuts = cuts end def twist? @res.tally.values.max > 1 end def read_cuts Roll.read(@cuts) end def read Roll.read(@res) end def interpret outcome = case @res.max when 1,2,3 "#{Term::RED}disaster#{Term::RESET}" when 4,5 "#{Term::YELLOW}conflict#{Term::RESET}" when 6 "#{Term::GREEN}triumph#{Term::RESET}" end "#{outcome}#{" with a #{Term::BLUE}twist#{Term::RESET}" if twist?}" end def cut_twist (1...@res.length).map do |i| res = Roll.new(@res[0...-i], @res[-i..-1] + @cuts) next if res.twist? return [i, res] end end def self.roll(number, cuts) res = self.roll_dice(number) new(*self.split(res, cuts)) end def self.read(ary) numword = { 1 => "a", 2 => "two", 3 => "three", 4 => "four", 5 => "five", 6 => "six" } readres = "" ary.tally.each do |val, num| readres += "#{numword[num]} #{Term::BOLD}#{val}#{Term::RESET}#{?s if num > 1}, " end readres = readres[0...-2] readres.sub!(/.*\K, /, " and ") readres end def self.roll_dice(num) Array.new(num) { rand(6) + 1 }.sort end def self.split(res, cutn) cuts = cutn > 0 ? res[-cutn..-1] : [] res = res[0...-cutn] if cutn > 0 [res, cuts] end end def prompt(msg) print Term::PURPLE print msg print ?? unless msg[-1] == ?? print ?\s print Term::RESET gets.to_i end trap("INT") do puts exit end loop do number = prompt "How many dice" break if number == 0 cuts = prompt "How many cuts" roll = Roll.roll(number, cuts) if cuts > 0 print " After cutting #{roll.read_cuts}, y" else print " Y" end print "ou rolled #{roll.read}. " puts "That's a #{roll.interpret}." if roll.twist? i, cutroll = roll.cut_twist puts " If you chose to cut #{i}#{" more" if cuts > 0}, it would just be a #{cutroll.interpret}." end end