diff --git a/config.json b/config.json index 89e3ac480c..50df3e154f 100644 --- a/config.json +++ b/config.json @@ -496,6 +496,12 @@ "difficulty": 1, "topics": [ ] + }, + { + "slug": "tournament", + "difficulty": 1, + "topics": [ + ] } ], "deprecated": [ diff --git a/exercises/tournament/.version b/exercises/tournament/.version new file mode 100644 index 0000000000..56a6051ca2 --- /dev/null +++ b/exercises/tournament/.version @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/exercises/tournament/example.rb b/exercises/tournament/example.rb new file mode 100644 index 0000000000..0c9160d5fe --- /dev/null +++ b/exercises/tournament/example.rb @@ -0,0 +1,54 @@ +module BookKeeping + VERSION = 1 +end + +class Tournament + def self.tally(input) + teams = Hash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = 0 } } + + input.split("\n").each do |line| + team_one, team_two, result = line.split(';') + + case result + when "win" + teams[team_one][:won] += 1 + teams[team_two][:loss] += 1 + when "loss" + teams[team_one][:loss] += 1 + teams[team_two][:won] += 1 + when "draw" + teams[team_one][:draw] += 1 + teams[team_two][:draw] += 1 + end + end + + teams.keys.each do |team_name| + team = teams[team_name] + team[:matches] = team[:won] + team[:loss] + team[:draw] + team[:points] = team[:won] * 3 + team[:draw] + end + + team_order = + teams + .to_a + .sort_by { |team| [-team[1][:points], team[0]] } + .map(&:first) + + result = ['Team | MP | W | D | L | P'] + + team_order.each do |team_name| + stats = teams[team_name] + + result << [ + team_name.ljust(30), + stats[:matches], + stats[:won], + stats[:draw], + stats[:loss], + stats[:points] + ].join(' | ') + end + + result.join("\n") + "\n" + end +end diff --git a/exercises/tournament/example.tt b/exercises/tournament/example.tt new file mode 100644 index 0000000000..10e84d436a --- /dev/null +++ b/exercises/tournament/example.tt @@ -0,0 +1,23 @@ +#!/usr/bin/env ruby +gem 'minitest', '>= 5.0.0' +require 'minitest/autorun' +require_relative 'tournament' + +# Test data version: +# <%= sha1 %> +class TournamentTest < Minitest::Test +<% test_cases.each do |test_case| %> + def <%= test_case.test_name %> + <%= test_case.skipped %> + input = <%= test_case.input_text %> + actual = <%= test_case.workload %> + expected = <%= test_case.expect %> + assert_equal expected, actual + end +<% end %> +<%= IO.read(XRUBY_LIB + '/bookkeeping.md') %> + def test_bookkeeping + skip + assert_equal <%= version.next %>, BookKeeping::VERSION + end +end diff --git a/exercises/tournament/tournament_test.rb b/exercises/tournament/tournament_test.rb new file mode 100755 index 0000000000..17a838152a --- /dev/null +++ b/exercises/tournament/tournament_test.rb @@ -0,0 +1,92 @@ +#!/usr/bin/env ruby +gem 'minitest', '>= 5.0.0' +require 'minitest/autorun' +require_relative 'tournament' + +# Test data version: +# 0a51cfc +class TournamentTest < Minitest::Test + + def test_typical_input + # skip + input = <<-INPUT.gsub(/^ */, '') + Allegoric Alaskans;Blithering Badgers;win + Devastating Donkeys;Courageous Californians;draw + Devastating Donkeys;Allegoric Alaskans;win + Courageous Californians;Blithering Badgers;loss + Blithering Badgers;Devastating Donkeys;loss + Allegoric Alaskans;Courageous Californians;win + INPUT + actual = Tournament.tally(input) + expected = <<-TALLY.gsub(/^ */, '') + Team | MP | W | D | L | P + Devastating Donkeys | 3 | 2 | 1 | 0 | 7 + Allegoric Alaskans | 3 | 2 | 0 | 1 | 6 + Blithering Badgers | 3 | 1 | 0 | 2 | 3 + Courageous Californians | 3 | 0 | 1 | 2 | 1 + TALLY + assert_equal expected, actual + end + + def test_incomplete_competition_not_all_pairs_have_played + skip + input = <<-INPUT.gsub(/^ */, '') + Allegoric Alaskans;Blithering Badgers;loss + Devastating Donkeys;Allegoric Alaskans;loss + Courageous Californians;Blithering Badgers;draw + Allegoric Alaskans;Courageous Californians;win + INPUT + actual = Tournament.tally(input) + expected = <<-TALLY.gsub(/^ */, '') + Team | MP | W | D | L | P + Allegoric Alaskans | 3 | 2 | 0 | 1 | 6 + Blithering Badgers | 2 | 1 | 1 | 0 | 4 + Courageous Californians | 2 | 0 | 1 | 1 | 1 + Devastating Donkeys | 1 | 0 | 0 | 1 | 0 + TALLY + assert_equal expected, actual + end + + def test_ties_broken_alphabetically + skip + input = <<-INPUT.gsub(/^ */, '') + Courageous Californians;Devastating Donkeys;win + Allegoric Alaskans;Blithering Badgers;win + Devastating Donkeys;Allegoric Alaskans;loss + Courageous Californians;Blithering Badgers;win + Blithering Badgers;Devastating Donkeys;draw + Allegoric Alaskans;Courageous Californians;draw + INPUT + actual = Tournament.tally(input) + expected = <<-TALLY.gsub(/^ */, '') + Team | MP | W | D | L | P + Allegoric Alaskans | 3 | 2 | 1 | 0 | 7 + Courageous Californians | 3 | 2 | 1 | 0 | 7 + Blithering Badgers | 3 | 0 | 1 | 2 | 1 + Devastating Donkeys | 3 | 0 | 1 | 2 | 1 + TALLY + assert_equal expected, actual + end + + # Problems in exercism evolve over time, as we find better ways to ask + # questions. + # The version number refers to the version of the problem you solved, + # not your solution. + # + # Define a constant named VERSION inside of the top level BookKeeping + # module, which may be placed near the end of your file. + # + # In your file, it will look like this: + # + # module BookKeeping + # VERSION = 1 # Where the version number matches the one in the test. + # end + # + # If you are curious, read more about constants on RubyDoc: + # http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html + + def test_bookkeeping + skip + assert_equal 1, BookKeeping::VERSION + end +end diff --git a/lib/tournament_cases.rb b/lib/tournament_cases.rb new file mode 100644 index 0000000000..a4f8b82d30 --- /dev/null +++ b/lib/tournament_cases.rb @@ -0,0 +1,45 @@ +class TournamentCase < OpenStruct + def test_name + "test_#{description.tr(' ', '_').tr('()', '')}" + end + + def skipped + index.zero? ? '# skip' : 'skip' + end + + def workload + 'Tournament.tally(input)' + end + + def expect + indented_heredoc(expected, 'TALLY') + end + + def input_text + indented_heredoc(input, 'INPUT') + end + + private + + def indented_heredoc(string, delimiter) + [ + "<<-#{delimiter}.gsub(/^ */, '')", + indent_lines(string), + indent_line(delimiter) + ].join("\n") + end + + def indent_lines(lines, indent = 3) + lines.map { |line| indent_line(line, indent) }.join("\n") + end + + def indent_line(line, indent = 2) + ' ' * indent * 2 + line + end +end + +TournamentCases = proc do |data| + JSON.parse(data)['valid_inputs']['cases'].map.with_index do |row, i| + TournamentCase.new(row.merge('index' => i)) + end +end