diff --git a/config.json b/config.json index ca3e923..e1a56d6 100644 --- a/config.json +++ b/config.json @@ -560,6 +560,14 @@ "prerequisites": [], "difficulty": 2 }, + { + "slug": "tournament", + "name": "Tournament", + "uuid": "452756cd-f85d-4853-8775-59a15abdc61e", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "triangle", "name": "Triangle", diff --git a/exercises/practice/tournament/.docs/instructions.md b/exercises/practice/tournament/.docs/instructions.md new file mode 100644 index 0000000..e5ca237 --- /dev/null +++ b/exercises/practice/tournament/.docs/instructions.md @@ -0,0 +1,66 @@ +# Instructions + +Tally the results of a small football competition. + +Based on an input file containing which team played against which and what the outcome was, create a file with a table like this: + +```text +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 +``` + +What do those abbreviations mean? + +- MP: Matches Played +- W: Matches Won +- D: Matches Drawn (Tied) +- L: Matches Lost +- P: Points + +A win earns a team 3 points. +A draw earns 1. +A loss earns 0. + +The outcome is ordered by points, descending. +In case of a tie, teams are ordered alphabetically. + +## Input + +Your tallying program will receive input that looks like: + +```text +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 +``` + +The result of the match refers to the first team listed. +So this line: + +```text +Allegoric Alaskans;Blithering Badgers;win +``` + +means that the Allegoric Alaskans beat the Blithering Badgers. + +This line: + +```text +Courageous Californians;Blithering Badgers;loss +``` + +means that the Blithering Badgers beat the Courageous Californians. + +And this line: + +```text +Devastating Donkeys;Courageous Californians;draw +``` + +means that the Devastating Donkeys and Courageous Californians tied. diff --git a/exercises/practice/tournament/.meta/config.json b/exercises/practice/tournament/.meta/config.json new file mode 100644 index 0000000..0e7ae68 --- /dev/null +++ b/exercises/practice/tournament/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "tournament.vim" + ], + "test": [ + "tournament.vader" + ], + "example": [ + ".meta/example.vim" + ] + }, + "blurb": "Tally the results of a small football competition." +} diff --git a/exercises/practice/tournament/.meta/example.vim b/exercises/practice/tournament/.meta/example.vim new file mode 100644 index 0000000..fea15e5 --- /dev/null +++ b/exercises/practice/tournament/.meta/example.vim @@ -0,0 +1,79 @@ +let s:HEADER = 'Team | MP | W | D | L | P' + +function! Tally(lines) abort + if empty(a:lines) + return [s:HEADER] + endif + + let l:team_data = s:ProcessGameResults(a:lines) + let l:team_standings = s:PrepareStandings(l:team_data) + let l:rows = s:BuildTableRows(l:team_standings) + + return [s:HEADER] + l:rows +endfunction + +function! s:ProcessGameResults(lines) abort + let l:teams = {} + for l:line in a:lines + let [l:team1, l:team2, l:result] = split(l:line, ';') + + if !has_key(l:teams, l:team1) + let l:teams[l:team1] = {'name': l:team1, 'W': 0, 'D': 0, 'L': 0} + endif + + if !has_key(l:teams, l:team2) + let l:teams[l:team2] = {'name': l:team2, 'W': 0, 'D': 0, 'L': 0} + endif + + if l:result ==? 'win' + let l:teams[l:team1]['W'] += 1 + let l:teams[l:team2]['L'] += 1 + elseif l:result ==? 'loss' + let l:teams[l:team1]['L'] += 1 + let l:teams[l:team2]['W'] += 1 + elseif l:result ==? 'draw' + let l:teams[l:team1]['D'] += 1 + let l:teams[l:team2]['D'] += 1 + endif + endfor + + return l:teams +endfunction + +function! s:PrepareStandings(teams) abort + let l:standings = [] + for l:team in keys(a:teams) + let l:team_data = a:teams[l:team] + let l:team_data['MP'] = l:team_data['W'] + l:team_data['D'] + l:team_data['L'] + let l:team_data['P'] = l:team_data['W'] * 3 + l:team_data['D'] + call add(l:standings, l:team_data) + endfor + + call sort(l:standings, 's:SortTeams') + + return l:standings +endfunction + +function! s:BuildTableRows(teams) abort + let l:rows = [] + for l:team_data in a:teams + let l:row = printf('%-30s | %2d | %2d | %2d | %2d | %2d', + \ l:team_data['name'], + \ l:team_data['MP'], + \ l:team_data['W'], + \ l:team_data['D'], + \ l:team_data['L'], + \ l:team_data['P']) + call add(l:rows, l:row) + endfor + + return l:rows +endfunction + +function! s:SortTeams(teamA, teamB) abort + if a:teamA['P'] ==? a:teamB['P'] + return a:teamA['name'] > a:teamB['name'] + endif + + return a:teamA['P'] < a:teamB['P'] +endfunction diff --git a/exercises/practice/tournament/.meta/tests.toml b/exercises/practice/tournament/.meta/tests.toml new file mode 100644 index 0000000..0e33c87 --- /dev/null +++ b/exercises/practice/tournament/.meta/tests.toml @@ -0,0 +1,46 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[67e9fab1-07c1-49cf-9159-bc8671cc7c9c] +description = "just the header if no input" + +[1b4a8aef-0734-4007-80a2-0626178c88f4] +description = "a win is three points, a loss is zero points" + +[5f45ac09-4efe-46e7-8ddb-75ad85f86e05] +description = "a win can also be expressed as a loss" + +[fd297368-efa0-442d-9f37-dd3f9a437239] +description = "a different team can win" + +[26c016f9-e753-4a93-94e9-842f7b4d70fc] +description = "a draw is one point each" + +[731204f6-4f34-4928-97eb-1c307ba83e62] +description = "There can be more than one match" + +[49dc2463-42af-4ea6-95dc-f06cc5776adf] +description = "There can be more than one winner" + +[6d930f33-435c-4e6f-9e2d-63fa85ce7dc7] +description = "There can be more than two teams" + +[97022974-0c8a-4a50-8fe7-e36bdd8a5945] +description = "typical input" + +[fe562f0d-ac0a-4c62-b9c9-44ee3236392b] +description = "incomplete competition (not all pairs have played)" + +[3aa0386f-150b-4f99-90bb-5195e7b7d3b8] +description = "ties broken alphabetically" + +[f9e20931-8a65-442a-81f6-503c0205b17a] +description = "ensure points sorted numerically" diff --git a/exercises/practice/tournament/tournament.vader b/exercises/practice/tournament/tournament.vader new file mode 100644 index 0000000..33930f8 --- /dev/null +++ b/exercises/practice/tournament/tournament.vader @@ -0,0 +1,59 @@ +Execute (just the header if no input): + let g:rows = [] + let g:expected = ['Team | MP | W | D | L | P'] + AssertEqual g:expected, Tally(g:rows) + +Execute (a win is three points, a loss is zero points): + let g:rows = ['Allegoric Alaskans;Blithering Badgers;win'] + let g:expected = ['Team | MP | W | D | L | P', 'Allegoric Alaskans | 1 | 1 | 0 | 0 | 3', 'Blithering Badgers | 1 | 0 | 0 | 1 | 0'] + AssertEqual g:expected, Tally(g:rows) + +Execute (a win can also be expressed as a loss): + let g:rows = ['Blithering Badgers;Allegoric Alaskans;loss'] + let g:expected = ['Team | MP | W | D | L | P', 'Allegoric Alaskans | 1 | 1 | 0 | 0 | 3', 'Blithering Badgers | 1 | 0 | 0 | 1 | 0'] + AssertEqual g:expected, Tally(g:rows) + +Execute (a different team can win): + let g:rows = ['Blithering Badgers;Allegoric Alaskans;win'] + let g:expected = ['Team | MP | W | D | L | P', 'Blithering Badgers | 1 | 1 | 0 | 0 | 3', 'Allegoric Alaskans | 1 | 0 | 0 | 1 | 0'] + AssertEqual g:expected, Tally(g:rows) + +Execute (a draw is one point each): + let g:rows = ['Allegoric Alaskans;Blithering Badgers;draw'] + let g:expected = ['Team | MP | W | D | L | P', 'Allegoric Alaskans | 1 | 0 | 1 | 0 | 1', 'Blithering Badgers | 1 | 0 | 1 | 0 | 1'] + AssertEqual g:expected, Tally(g:rows) + +Execute (There can be more than one match): + let g:rows = ['Allegoric Alaskans;Blithering Badgers;win', 'Allegoric Alaskans;Blithering Badgers;win'] + let g:expected = ['Team | MP | W | D | L | P', 'Allegoric Alaskans | 2 | 2 | 0 | 0 | 6', 'Blithering Badgers | 2 | 0 | 0 | 2 | 0'] + AssertEqual g:expected, Tally(g:rows) + +Execute (There can be more than one winner): + let g:rows = ['Allegoric Alaskans;Blithering Badgers;loss', 'Allegoric Alaskans;Blithering Badgers;win'] + let g:expected = ['Team | MP | W | D | L | P', 'Allegoric Alaskans | 2 | 1 | 0 | 1 | 3', 'Blithering Badgers | 2 | 1 | 0 | 1 | 3'] + AssertEqual g:expected, Tally(g:rows) + +Execute (There can be more than two teams): + let g:rows = ['Allegoric Alaskans;Blithering Badgers;win', 'Blithering Badgers;Courageous Californians;win', 'Courageous Californians;Allegoric Alaskans;loss'] + let g:expected = ['Team | MP | W | D | L | P', 'Allegoric Alaskans | 2 | 2 | 0 | 0 | 6', 'Blithering Badgers | 2 | 1 | 0 | 1 | 3', 'Courageous Californians | 2 | 0 | 0 | 2 | 0'] + AssertEqual g:expected, Tally(g:rows) + +Execute (typical input): + let g:rows = ['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'] + let g:expected = ['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'] + AssertEqual g:expected, Tally(g:rows) + +Execute (incomplete competition (not all pairs have played)): + let g:rows = ['Allegoric Alaskans;Blithering Badgers;loss', 'Devastating Donkeys;Allegoric Alaskans;loss', 'Courageous Californians;Blithering Badgers;draw', 'Allegoric Alaskans;Courageous Californians;win'] + let g:expected = ['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'] + AssertEqual g:expected, Tally(g:rows) + +Execute (ties broken alphabetically): + let g:rows = ['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'] + let g:expected = ['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'] + AssertEqual g:expected, Tally(g:rows) + +Execute (ensure points sorted numerically): + let g:rows = ['Devastating Donkeys;Blithering Badgers;win', 'Devastating Donkeys;Blithering Badgers;win', 'Devastating Donkeys;Blithering Badgers;win', 'Devastating Donkeys;Blithering Badgers;win', 'Blithering Badgers;Devastating Donkeys;win'] + let g:expected = ['Team | MP | W | D | L | P', 'Devastating Donkeys | 5 | 4 | 0 | 1 | 12', 'Blithering Badgers | 5 | 1 | 0 | 4 | 3'] + AssertEqual g:expected, Tally(g:rows) diff --git a/exercises/practice/tournament/tournament.vim b/exercises/practice/tournament/tournament.vim new file mode 100644 index 0000000..9f55c59 --- /dev/null +++ b/exercises/practice/tournament/tournament.vim @@ -0,0 +1,3 @@ +function! Tally(lines) abort + " your code goes here +endfunction