tennis 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Makefile +1 -1
- data/lib/tennis/version.rb +1 -1
- data/lib/tennis.rb +48 -150
- data/spec/tennis_spec.rb +13 -59
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ce621f74414d103564e2bcc239a788d487c912ee
|
|
4
|
+
data.tar.gz: 7fb8ec8e853cf6b05f775aed1ad42a95fe982d34
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e693fb0265a8e3934b631971f86a57320003ac1fe82863ad840478cc3ab57cf5107f98e9d314483ee8b6a5fe59338ea45e2723b7d7a06f2752e94d35f1974ec4
|
|
7
|
+
data.tar.gz: f69de2817fda3554545f98af969f1dbf6d2dbceafff7f43c3b6109d0adbb3fde5889bc4ad870ad8a893ca8b7966dd8698ff76e9fe8f1277d63ad77717796ee7d
|
data/Makefile
CHANGED
data/lib/tennis/version.rb
CHANGED
data/lib/tennis.rb
CHANGED
|
@@ -4,180 +4,78 @@ class Tennis
|
|
|
4
4
|
# player 1 is the home player(0) , player 2 is the away player(1)
|
|
5
5
|
# winner is either 0 or 1
|
|
6
6
|
# points is an array: [points for 0 , points for 1]
|
|
7
|
-
#
|
|
8
|
-
#
|
|
7
|
+
# sets_won/lost is an array: [sets won/lost by 0, sets won/lost by 1]
|
|
8
|
+
# games_won/lost is an array: [games won/lost by 0, games won/lost by 1]
|
|
9
9
|
|
|
10
|
-
attr_reader :winner, :
|
|
10
|
+
attr_reader :winner, :sets_won, :sets_lost, :games_won, :games_lost
|
|
11
11
|
|
|
12
|
-
def initialize(
|
|
12
|
+
def initialize(score)
|
|
13
13
|
# dfh -> default win for home player(0)
|
|
14
14
|
# dfa -> default win for away player(1)
|
|
15
|
-
|
|
16
|
-
@scores = validate_score(scores)
|
|
17
|
-
@winner = match_winner if @winner == :default
|
|
18
|
-
@points = match_points
|
|
19
|
-
unless @scores.is_a? String
|
|
20
|
-
@sets_lost = count_sets_lost
|
|
21
|
-
@games_lost = count_games_lost
|
|
22
|
-
end
|
|
15
|
+
process_score(score)
|
|
23
16
|
end
|
|
24
17
|
|
|
25
18
|
# to_s
|
|
26
19
|
# return the score in string format
|
|
27
20
|
def to_s
|
|
28
|
-
|
|
21
|
+
@score.map{|set| set.join('-') }.join(', ')
|
|
29
22
|
end
|
|
30
23
|
|
|
31
24
|
# flip score ( P1-P2 to P2-P1)
|
|
32
25
|
# returns the flipped score as a string
|
|
33
26
|
def flipped
|
|
34
|
-
|
|
27
|
+
@score.map{|set| set.reverse.join('-') }.join(', ')
|
|
35
28
|
end
|
|
36
29
|
|
|
37
30
|
private
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
set_scores
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# returns who won the match
|
|
65
|
-
# :incomplete_match (bad input/incomplete match)
|
|
66
|
-
# :error (bad input for sure)
|
|
67
|
-
# 0 (player-1 won)
|
|
68
|
-
# 1 (player-2 won)
|
|
69
|
-
def match_winner
|
|
70
|
-
@scores.length == 4 ? two_sets : three_sets
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# returns an array of points
|
|
74
|
-
# returns (points_player_1 , points_player_2)
|
|
75
|
-
# returns (0,0) for bad input
|
|
76
|
-
def match_points
|
|
77
|
-
return [0, 0] if @winner == :error
|
|
78
|
-
return [@scores == 'dfh' ? 12 : 0, @scores == 'dfa' ? 12 : 0] if @scores.is_a? String
|
|
79
|
-
@winner == 0 || @winner == 1 ? complete_match_points : incomplete_match_points
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# returns the number of sets lost by each player
|
|
83
|
-
def count_sets_lost
|
|
84
|
-
sets = [0, 0]
|
|
85
|
-
(0...@scores.length).step(2).each do |i|
|
|
86
|
-
@scores[i] > @scores[i + 1] ? sets[1] += 1 : sets[0] += 1
|
|
87
|
-
end
|
|
88
|
-
sets
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# returns the number of won by each player
|
|
92
|
-
def count_games_lost
|
|
93
|
-
games = [0, 0]
|
|
94
|
-
(0...@scores.length).step(2).each do |i|
|
|
95
|
-
games[0] += @scores[i + 1]
|
|
96
|
-
games[1] += @scores[i]
|
|
32
|
+
def process_score(score, best_of=3)
|
|
33
|
+
begin
|
|
34
|
+
sets = score.split(/,/)
|
|
35
|
+
# only take 2 to 5 sets
|
|
36
|
+
raise "invalid number of sets" unless (2..best_of).cover? sets.length
|
|
37
|
+
score_plus_winner = map_scores_winners(sets)
|
|
38
|
+
@set_winners = score_plus_winner.map{ |sw| sw[1] }
|
|
39
|
+
home = @set_winners.count(0)
|
|
40
|
+
away = @set_winners.count(1)
|
|
41
|
+
raise "nobody won" if home + away == 0
|
|
42
|
+
@winner = home > away ? 0 : away > home ? 1 : raise("no winner")
|
|
43
|
+
# sets won and lost
|
|
44
|
+
@sets_won, @sets_lost = [[home, away], [away, home]]
|
|
45
|
+
# score array
|
|
46
|
+
@score = score_plus_winner.map{ |sw| sw[0] }
|
|
47
|
+
@games_won = @score.transpose.map{ |games| games.inject{ |sum,x| sum + x } }
|
|
48
|
+
@games_lost = @games_won.reverse
|
|
49
|
+
# FIXME this is the only thing that assumes 3 sets
|
|
50
|
+
raise "too many sets" if @set_winners[0] == @set_winners[1] and sets.size > 2
|
|
51
|
+
rescue => e
|
|
52
|
+
raise ArgumentError, "Invalid score '#{score}': #{e}"
|
|
97
53
|
end
|
|
98
|
-
games
|
|
99
54
|
end
|
|
100
55
|
|
|
101
|
-
#
|
|
102
|
-
def
|
|
103
|
-
sets
|
|
104
|
-
|
|
105
|
-
|
|
56
|
+
# return an array of scores and winners for each set
|
|
57
|
+
def map_scores_winners(sets)
|
|
58
|
+
sets.map do |set|
|
|
59
|
+
set.strip!
|
|
60
|
+
games = set.split(/-/).map(&:to_i)
|
|
61
|
+
raise "uneven games in set '#{set}'" unless games.length == 2
|
|
62
|
+
h, a = games
|
|
63
|
+
sw = set_winner(h, a)
|
|
64
|
+
raise "no valid winner in set '#{set}'" unless sw
|
|
65
|
+
[games, sw]
|
|
106
66
|
end
|
|
107
|
-
sets
|
|
108
67
|
end
|
|
109
68
|
|
|
110
|
-
#
|
|
111
|
-
def
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
69
|
+
# determine the set winner for home and away, or else return nil
|
|
70
|
+
def set_winner(h, a)
|
|
71
|
+
# basic range check
|
|
72
|
+
return nil if h > 7 or a > 7 or h < 0 or a < 0
|
|
73
|
+
# game went to 7
|
|
74
|
+
return 0 if h == 7 and [5,6].include?(a)
|
|
75
|
+
return 1 if a == 7 and [5,6].include?(h)
|
|
76
|
+
# there has to be one winner, to 6
|
|
77
|
+
return nil unless (h == 6 and h > a + 1) or (a == 6 and a > h + 1)
|
|
78
|
+
h > a ? 0 : 1
|
|
118
79
|
end
|
|
119
80
|
|
|
120
|
-
# helper method: called by RESULT method for valid matches with 2 sets
|
|
121
|
-
def two_sets
|
|
122
|
-
set_results = []
|
|
123
|
-
(0...@scores.length).step(2).each do |i|
|
|
124
|
-
# tie breaker (assuming a 7 point tie breaker) or a 7-5 scores
|
|
125
|
-
if @scores[i] == 7 || @scores[i + 1] == 7
|
|
126
|
-
set_results << (@scores[i] == 7 ? 0 : 1)
|
|
127
|
-
# regular set victory - 6 games with a margin of 2
|
|
128
|
-
else
|
|
129
|
-
return :incomplete_match if ( @scores[i] - @scores[i + 1] ).abs < 2
|
|
130
|
-
set_results << (@scores[i] == 6 ? 0 : 1)
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
# incomplete match e.g: 6-4,5-3
|
|
134
|
-
(set_results[0] if set_results[0] == set_results[1]) || :incomplete_match
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
# helper method: called by RESULT method for valid matches with 3 sets
|
|
138
|
-
def three_sets
|
|
139
|
-
set_results = []
|
|
140
|
-
(0...@scores.length).step(2).each do |i|
|
|
141
|
-
# tie breaker (assuming a 7 point tie breaker) or a 7-5 score
|
|
142
|
-
if @scores[i] == 7 || @scores[i + 1] == 7
|
|
143
|
-
set_results << (@scores[i] == 7 ? 0 : 1)
|
|
144
|
-
# regular set victory - 6 games with a margin of 2
|
|
145
|
-
else
|
|
146
|
-
return :incomplete_match if (@scores[i] - @scores[i + 1]).abs < 2
|
|
147
|
-
set_results << (@scores[i] == 6 ? 0 : 1)
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
# checks if the result has been decided in the first 2 sets
|
|
151
|
-
# but the 3rd set is also present in the input
|
|
152
|
-
return :error if set_results[0] == set_results[1]
|
|
153
|
-
set_results.count(0) == 2 ? 0 : 1
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
# helper method: called by POINTS for complete matches
|
|
157
|
-
def complete_match_points
|
|
158
|
-
points = [0, 0]
|
|
159
|
-
points[@winner] = (@scores.length == 6) ? 12 : 14
|
|
160
|
-
runner_up = 1 - @winner
|
|
161
|
-
runner_up_points = player_points(runner_up)
|
|
162
|
-
points[runner_up] = runner_up_points < 8 ? runner_up_points : 8
|
|
163
|
-
points
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
# helper method: called by POINTS for incomplete matches
|
|
167
|
-
def incomplete_match_points
|
|
168
|
-
points = [0, 0]
|
|
169
|
-
player_1_points = player_points(0)
|
|
170
|
-
player_2_points = player_points(1)
|
|
171
|
-
points[0] = player_1_points < 10 ? player_1_points : 10
|
|
172
|
-
points[1] = player_2_points < 10 ? player_2_points : 10
|
|
173
|
-
points
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
# helper method: returns the POINTS of a player given the player number
|
|
177
|
-
def player_points(player)
|
|
178
|
-
player_scores = []
|
|
179
|
-
@scores.each_with_index { |score, index| (player_scores << score; player += 2) if index == (player) }
|
|
180
|
-
player_scores = player_scores.sort! { |x, y| y <=> x }
|
|
181
|
-
player_scores[0] + player_scores[1]
|
|
182
|
-
end
|
|
183
81
|
end
|
data/spec/tennis_spec.rb
CHANGED
|
@@ -28,90 +28,44 @@ describe Tennis, "#scores" do
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
it "reports incomplete match score (set 1-1)" do
|
|
31
|
-
|
|
32
|
-
expect(score.winner).to eq :incomplete_match
|
|
31
|
+
expect { Tennis.new("6-4,4-6") }.to raise_error
|
|
33
32
|
end
|
|
34
33
|
|
|
35
34
|
it "reports incomplete match score (set incomplete)" do
|
|
36
|
-
|
|
37
|
-
expect(score.winner).to eq :incomplete_match
|
|
35
|
+
expect { Tennis.new("6-4,4-5") }.to raise_error
|
|
38
36
|
end
|
|
39
37
|
|
|
40
38
|
it "checks invalid score: difference in games won < 2" do
|
|
41
|
-
|
|
42
|
-
expect(score.winner).to eq :incomplete_match
|
|
39
|
+
expect { Tennis.new("6-5,4-6,7-6") }.to raise_error
|
|
43
40
|
end
|
|
44
41
|
|
|
45
42
|
it "checks invalid score: only 1 set input" do
|
|
46
|
-
|
|
47
|
-
expect(score.winner).to eq :error
|
|
43
|
+
expect { Tennis.new("6-4") }.to raise_error
|
|
48
44
|
end
|
|
49
45
|
|
|
50
46
|
it "checks invalid score: winner decided in first 2 sets but 3rd set input" do
|
|
51
|
-
|
|
52
|
-
expect(score.winner).to eq :error
|
|
47
|
+
expect { Tennis.new("6-4,6-4,4-6") }.to raise_error
|
|
53
48
|
end
|
|
54
49
|
|
|
55
50
|
it "checks invalid score: bad input for tie break" do
|
|
56
|
-
|
|
57
|
-
expect(score.winner).to eq :error
|
|
51
|
+
expect { Tennis.new("7-0,4-6,6-2") }.to raise_error
|
|
58
52
|
end
|
|
59
53
|
|
|
60
54
|
it "checks invalid score: no score > 7" do
|
|
61
|
-
|
|
62
|
-
expect(score.winner).to eq :error
|
|
55
|
+
expect { Tennis.new("8-4,2-6,6-1") }.to raise_error
|
|
63
56
|
end
|
|
64
57
|
|
|
65
|
-
it "checks invalid score: blank score ''
|
|
66
|
-
|
|
67
|
-
expect(score.winner).to eq :error
|
|
58
|
+
it "checks invalid score: blank score ''" do
|
|
59
|
+
expect { Tennis.new("") }.to raise_error
|
|
68
60
|
end
|
|
69
61
|
|
|
70
62
|
it "finds the winner properly in scores with 7-5" do
|
|
71
63
|
score = Tennis.new("3-6,5-7")
|
|
72
64
|
expect(score.winner).to eq 1
|
|
73
65
|
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
describe Tennis, "#points" do
|
|
77
|
-
it "returns 12 points in a three set win in a complete match" do
|
|
78
|
-
score = Tennis.new("6-4, 4-6, 6-4")
|
|
79
|
-
expect(score.points).to eq [12,8]
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
it "returns 14 points in two set win in a complete match" do
|
|
83
|
-
score = Tennis.new("4-6, 4-6")
|
|
84
|
-
expect(score.points).to eq [8,14]
|
|
85
|
-
end
|
|
86
66
|
|
|
87
|
-
it "
|
|
88
|
-
|
|
89
|
-
expect(score.points).to eq [8,12]
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
it "return a max of 10 points for each player in an incomplete match" do
|
|
93
|
-
score = Tennis.new("7-6,6-7")
|
|
94
|
-
expect(score.points).to eq [10,10]
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
it "return a max of 10 points for each player in an incomplete match" do
|
|
98
|
-
score = Tennis.new("7-6,4-6,4-1")
|
|
99
|
-
expect(score.points).to eq [10,10]
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
it "return [0,0] for bad input" do
|
|
103
|
-
score = Tennis.new("8-1")
|
|
104
|
-
expect(score.points).to eq [0,0]
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
it "checks invalid score: blank score '' " do
|
|
108
|
-
score = Tennis.new("")
|
|
109
|
-
expect(score.points).to eq [0,0]
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
it "finds the points properly in scores with 7-5" do
|
|
113
|
-
score = Tennis.new("3-6,5-7")
|
|
114
|
-
expect(score.points).to eq [8,14]
|
|
67
|
+
it "raises exception for bad input" do
|
|
68
|
+
expect { Tennis.new("8-1") }.to raise_error
|
|
115
69
|
end
|
|
116
70
|
end
|
|
117
71
|
|
|
@@ -138,7 +92,7 @@ end
|
|
|
138
92
|
|
|
139
93
|
describe Tennis, "#sets_lost" do
|
|
140
94
|
it "returns the sets lost by each player" do
|
|
141
|
-
scores = [["6-4, 4-6, 6-4", [1,2]],["6-2,6-1", [0, 2]], ["7-6,4-6,6-4", [1, 2]], ["6-4", [0,
|
|
95
|
+
scores = [["6-4, 4-6, 6-4", [1,2]],["6-2,6-1", [0, 2]], ["7-6,4-6,6-4", [1, 2]], ["6-4, 6-1", [0, 2]]]
|
|
142
96
|
scores.each do |s|
|
|
143
97
|
ts = Tennis.new(s[0])
|
|
144
98
|
expect(ts.sets_lost).to eq s[1]
|
|
@@ -148,7 +102,7 @@ end
|
|
|
148
102
|
|
|
149
103
|
describe Tennis, "#games_lost" do
|
|
150
104
|
it "returns the games won by each player" do
|
|
151
|
-
scores = [["6-4, 4-6, 6-4", [14,16]],["6-2,6-1", [3, 12]], ["7-6,4-6,6-4", [16, 17]], ["6-4", [
|
|
105
|
+
scores = [["6-4, 4-6, 6-4", [14,16]],["6-2,6-1", [3, 12]], ["7-6,4-6,6-4", [16, 17]], ["6-4, 7-5", [9, 13]]]
|
|
152
106
|
scores.each do |s|
|
|
153
107
|
ts = Tennis.new(s[0])
|
|
154
108
|
expect(ts.games_lost).to eq s[1]
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tennis
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rohan Katyal
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2015-02-
|
|
12
|
+
date: 2015-02-16 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: bundler
|