diff options
-rwxr-xr-x | dartbot.rb | 196 |
1 files changed, 152 insertions, 44 deletions
@@ -1,5 +1,7 @@ #!/usr/bin/env ruby +require 'curses' + HORIZONTAL_STDEV = 24 VERTICAL_STDEV = 24 @@ -195,7 +197,6 @@ def play_visit(rem) v_rem = rem darts = [] - bust = false 3.times do t_angle, t_radius = next_dart(v_rem, 3 - darts.length) @@ -210,14 +211,13 @@ def play_visit(rem) (v_rem == 0 && segment != 'BULL' && segment !~ /^D/)) v_rem = rem - bust = true break end break if v_rem.zero? end - [v_rem, rem - v_rem, darts, bust] + [v_rem, rem - v_rem, darts] end def colour_points(points) @@ -240,33 +240,79 @@ def colour_points(points) end end +def curses_output_points(win, points) + win.addstr(' ') + + unless points + win.addstr(' ') + return + end + + str = "%3s" % points + + [180, 140, 100, 60, 40, 20, 1, 0].each do |pmin| + if points >= pmin + a = COLOUR_PAIRS["p#{pmin}".intern] + + win.attron(a) do + win.addstr(str) + end + break + end + end +end + +COLOURS = { + p180: [[82, 0], [Curses::A_BOLD]], + p140: [[82, 0]], + p100: [[154, 0]], + p60: [[226, 0]], + p40: [[214, 0]], + p20: [[202, 0]], + p1: [[196, 0]], + p0: [[196, 0], [Curses::A_BOLD]], + bw: [[0, 7]], + visit: [[235, 0]] +} + +COLOUR_PAIRS = {} + +def curses_init_colours + COLOURS.each.with_index do |(k, v), i| + Curses.init_pair(i + 1, *v[0]) + col = Curses.color_pair(i + 1) + if (mods = v[1]) + mods.each { |x| col |= x } + end + COLOUR_PAIRS[k] = col + end +end + def visit_darts(darts) str = darts.map { |x| '%3s' % x }.join(' ') str += ' ' * (3 - darts.length) str end -def output_visit(n, rem, points = nil, darts = nil, bust = false) +def output_visit(n, rem, points = nil, darts = nil) str = '(%2s) %3s' % [n, rem] str << ' %s' % colour_points(points) if points str << " \e[38;5;235m%s\e[0m" % visit_darts(darts) if darts - str << " \e[38;5;88mBUST\e[0m" if bust - str << " \e[38;5;76mWIN\e[0m" if rem.zero? puts str end -def output_int_visit(n, p_rem, rem, p_points = nil, points = nil, darts = nil, bust = false) - str = '(%2s) ' % n - str << (p_points ? colour_points(p_points) : ' ') - str << ' %3s' % p_rem - str << ' %3s' % rem - str << ' %s' % colour_points(points) if points - str << " \e[38;5;235m%s\e[0m" % visit_darts(darts) if darts - str << " \e[38;5;88mBUST\e[0m" if bust - str << " \e[38;5;76mWIN\e[0m" if rem.zero? - - puts str +def curses_output_visit(win, n, p_rem, rem, p_points = nil, points = nil, darts = nil) + win.addstr('(%2s)' % n) + curses_output_points(win, p_points) + win.addstr(' %3s' % p_rem) + win.addstr(' %3s' % rem) + curses_output_points(win, points) + if darts + win.attron(COLOUR_PAIRS[:visit]) do + win.addstr(' %s' % visit_darts(darts)) + end + end end def play_match(start_points = 501, output = true) @@ -276,10 +322,10 @@ def play_match(start_points = 501, output = true) output_visit(m_darts.length, rem) if output while rem != 0 - rem, points, darts, bust = play_visit(rem) + rem, points, darts = play_visit(rem) m_darts << darts - output_visit(m_darts.length, rem, points, darts, bust) if output + output_visit(m_darts.length, rem, points, darts) if output if rem.zero? && output puts @@ -292,52 +338,114 @@ def play_match(start_points = 501, output = true) m_darts end -def play_int_match(start_points = 501, output = true) +def test_average + avgs = (0..10000).map do |x| + m_darts = play_match(501, false) + req = (((m_darts.length - 1) * 3) + m_darts[-1].length) + (501.to_f / req * 3) + end + + avg = avgs.sum / avgs.length + stdev = Math.sqrt(avgs.sum { |x| (x - avg) ** 2 } / (avgs.length - 1)) + + puts + puts avg + puts stdev +end + +def play_curses_match(start_points = 501) + Curses.init_screen + Curses.start_color + curses_init_colours + Curses.curs_set(0) + Curses.noecho + win = Curses::Window.new(Curses.lines, Curses.cols, 0, 0) + m_lines = [] + draw(win, m_lines) + p_rem = start_points rem = start_points m_darts = [] - output_int_visit(m_darts.length, p_rem, rem) if output + m_lines << [m_darts.length, p_rem, rem] + p_buff = '' + + draw(win, m_lines) + status = nil loop do - rem, points, darts, bust = play_visit(rem) + p_buff = '' + loop do + c = win.getch + if c == Curses::Key::RESIZE + win.resize(Curses.lines, Curses.cols) + draw(win, m_lines, p_buff) + elsif c == 10 + break + elsif c == 127 + p_buff = p_buff[0..-2] + draw(win, m_lines, p_buff) + elsif c.chr >= '0' && c.chr <= '9' + p_buff << c + draw(win, m_lines, p_buff) + end + end + + p_points = p_buff.to_i + p_rem -= p_points + m_lines << [m_darts.length + 1, p_rem, rem, p_points, nil, nil] + if p_rem == 0 + status = 'You win! :)' + break + end + + rem, points, darts = play_visit(rem) m_darts << darts + m_lines[m_lines.length-1] = [m_darts.length, p_rem, rem, p_points, points, darts] + draw(win, m_lines) - output_int_visit(m_darts.length, p_rem, rem, nil, points, darts, bust) if output if rem == 0 - puts - puts 'Dartbot wins. :(' + status = 'Dartbot wins. :(' break end + end - print "Enter points: " - p_points = gets.to_i - p_rem -= p_points - output_int_visit(m_darts.length, p_rem, rem, p_points, points, darts, bust) if output - puts - if p_rem == 0 - puts 'You win! :)' - break + draw(win, m_lines, p_buff, status) + loop do + c = win.getch + if c == Curses::Key::RESIZE + win.resize(Curses.lines, Curses.cols) + draw(win, m_lines, p_buff, status) end end m_darts end -def test_average - avgs = (0..10000).map do |x| - m_darts = play_match(501, false) - req = (((m_darts.length - 1) * 3) + m_darts[-1].length) - (501.to_f / req * 3) +def draw(win, m_lines, buf = '', status = nil) + win.erase + win.box + win.setpos(0,2) + win.addstr("dartbot") + + max_ml = Curses.lines - 5 + + m_lines.last(max_ml).each.with_index do |line, i| + win.setpos(2+i, 2) + curses_output_visit(win, *line) end - avg = avgs.sum / avgs.length - stdev = Math.sqrt(avgs.sum { |x| (x - avg) ** 2 } / (avgs.length - 1)) + win.setpos(Curses.lines - 2, 1) + win.attron(COLOUR_PAIRS[:bw]) do + if status + win.addstr(status.ljust(Curses.cols-2)) + else + win.addstr(('Enter points: ' + buf).ljust(Curses.cols-2)) + end + end - puts - puts avg - puts stdev + win.refresh end -play_int_match +play_curses_match #test_average |