aboutsummaryrefslogtreecommitdiff
path: root/wildsea_roll
blob: abacd299d35feaf250ee40033d9c43338aff3d10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/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