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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 071d8da8d7b39b88163c917635cff96a913bafcd
4
- data.tar.gz: 63252be0e608ee1d0f597d36c0333d24b8256606
3
+ metadata.gz: ce621f74414d103564e2bcc239a788d487c912ee
4
+ data.tar.gz: 7fb8ec8e853cf6b05f775aed1ad42a95fe982d34
5
5
  SHA512:
6
- metadata.gz: e9a0401551a28c70dd2cd3106196c3ec3d8723ff603ed5ef7250c077e3d76c41f74747a698594fb58929c41c154cdfdb92c880b08814b639569732b4457e2d67
7
- data.tar.gz: 66c54ec51b6a0f6520d4caa602c3eacdd950eb43736c749da85a4f294cbca106b820cf8c35a4f9d0faa209be8cd24d2d5337f369b5ac61cc59186b4198986399
6
+ metadata.gz: e693fb0265a8e3934b631971f86a57320003ac1fe82863ad840478cc3ab57cf5107f98e9d314483ee8b6a5fe59338ea45e2723b7d7a06f2752e94d35f1974ec4
7
+ data.tar.gz: f69de2817fda3554545f98af969f1dbf6d2dbceafff7f43c3b6109d0adbb3fde5889bc4ad870ad8a893ca8b7966dd8698ff76e9fe8f1277d63ad77717796ee7d
data/Makefile CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- VERSION=0.1.6
2
+ VERSION=0.2.0
3
3
 
4
4
  all:
5
5
  rake spec
@@ -1,3 +1,3 @@
1
1
  class Tennis
2
- VERSION = "0.1.7"
2
+ VERSION = "0.2.0"
3
3
  end
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
- # sets_lost is an array: [sets lost by 0, sets lost by 1]
8
- # games_lost is an array: [games won by 0, games won by 1]
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, :points, :sets_lost, :games_lost
10
+ attr_reader :winner, :sets_won, :sets_lost, :games_won, :games_lost
11
11
 
12
- def initialize(scores)
12
+ def initialize(score)
13
13
  # dfh -> default win for home player(0)
14
14
  # dfa -> default win for away player(1)
15
- @winner = :default
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
- (0...@scores.length).step(2).map{ |i| [@scores[i], @scores[i+1]].join('-') }.join(', ')
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
- (0...@scores.length).step(2).map{ |i| [@scores[i+1], @scores[i]].join('-') }.join(', ')
27
+ @score.map{|set| set.reverse.join('-') }.join(', ')
35
28
  end
36
29
 
37
30
  private
38
31
 
39
- # helper method: to check score validation
40
- def validate_score(scores_string)
41
- set_scores = scores_string.split(/[-,,]/).map(&:to_i)
42
- if set_scores == [0]
43
- # checks bad default string value reported
44
- @winner = (0 if scores == 'dfh') || (1 if scores == 'dfa') || :error
45
- scores_string
46
- else
47
- # check blank input ''
48
- validation_1 = set_scores.any? { |score| score.nil? }
49
- # to check if score for only 1 set has been input
50
- validation_2 = set_scores.length == 2
51
- # to check if any input > 7
52
- validation_3 = set_scores.any? { |score| score > 7 }
53
- # to check if one of the input is 7 and the other is not 6
54
- # bad tie break input
55
- validation_4 = false
56
- set_scores.each_slice(2).each { |r| validation_4 = true if r.any? { |score| score == 7 } && !r.any? { |score| score == 6 || score == 5 } }
57
- @winner = :error if validation_1 || validation_2 || validation_3 || validation_4
58
- # if set score is not complete eg: 4-6,7-6,4-1
59
- set_scores.each_slice(2).each {|r| @winner = :incomplete_match if r[0] < 6 && r[1] < 6 } unless @winner == :error
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
- # returns the number of sets won by each player
102
- def sets_won
103
- sets = [0, 0]
104
- (0...@scores.length).step(2).each do |i|
105
- @scores[0 + i] > @scores[1 + i] ? sets[0] += 1 : sets[1] += 1
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
- # returns the number of won by each player
111
- def games_won
112
- games = [0, 0]
113
- (0...@scores.length).step(2).each do |i|
114
- games[0] += @scores[0 + i]
115
- games[1] += @scores[1 + i]
116
- end
117
- games
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
- score = Tennis.new("6-4,4-6")
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
- score = Tennis.new("6-4,4-5")
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
- score = Tennis.new("6-5,4-6,7-6")
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
- score = Tennis.new("6-4")
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
- score = Tennis.new("6-4,6-4,4-6")
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
- score = Tennis.new("7-0,4-6,6-2")
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
- score = Tennis.new("8-4,2-6,6-1")
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 '' " do
66
- score = Tennis.new("")
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 "returns a max of 8 points for the runners up in a complete match" do
88
- score = Tennis.new("4-6, 6-2, 3-6")
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,1]]]
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", [4,6]]]
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.1.7
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-13 00:00:00.000000000 Z
12
+ date: 2015-02-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler