bowling_score 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9093cf9fa2cb65cee1c551098f845f4d9e77ade8
4
+ data.tar.gz: 0f2f109de09c915dc150878aff286fe9c8b6bf56
5
+ SHA512:
6
+ metadata.gz: b5e2ae43c9a0f73a4fd1da3a1d25ff091bfc7e3a14d57c6199db16de898c04bf688fb2596f9713bd38dc04ee193845716e75f7a5cc9da20e24f69d25a5d63798
7
+ data.tar.gz: 13b2807760221a47366f7c19e2b965addd6bafda43b4a523c268d9939875bce59b21df009287a5f0b683feac620a61e76c7c95aad5864bc6c8317c19f2be5dea
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bowling_score.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Ian Choi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,6 @@
1
+ # BowlingScore
2
+
3
+ This gem supports score calculation for a bowling game given a string of comma separated representation
4
+ of integer. The scoring rule is based on http://bowling.about.com/od/rulesofthegame/a/bowlingscoring.htm and
5
+ https://en.wikipedia.org/wiki/Ten-pin_bowling#Scoring. The calculation consider the rules for strike and spare
6
+ rewarding.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bowling_score/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'bowling_score'
8
+ spec.version = BowlingScore::VERSION
9
+ spec.authors = ['Ian Choi']
10
+ spec.email = ['achiinto@gmail.com']
11
+ spec.summary = 'Bowling score calculator'
12
+ spec.description = 'Bowling score calculator support strike and spare rules
13
+ of rewarding. Taking string as scores.'
14
+ spec.homepage = ''
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.7'
23
+ spec.add_development_dependency 'rake', '~> 10.0'
24
+ end
@@ -0,0 +1,60 @@
1
+ module BowlingScore
2
+ # Score Calculator - taking an array or string of scores (integers)
3
+ # and calculate with strike and spare rewarding
4
+ class ScoreCalculator
5
+ def initialize(scores)
6
+ @scores = scores.is_a?(String) ? scores.split(',') : scores
7
+ @scores = @scores.map(&:to_i)
8
+ end
9
+
10
+ def calculate
11
+ _calculate_from_frame(0)
12
+ end
13
+
14
+ private
15
+
16
+ def _calculate_from_frame(index)
17
+ return 0 if _out_of_range?(index)
18
+ return _rewarded_frame(index) unless _without_bonus?(index)
19
+ _unrewarded_frame(index)
20
+ end
21
+
22
+ def _is_strike?(index)
23
+ @scores[index] == BowlingScore::NUMBER_OF_PINS
24
+ end
25
+
26
+ def _without_bonus?(index)
27
+ current_score = @scores[index] || 0
28
+ next_score = @scores[index + 1] || 0
29
+ (current_score + next_score) < BowlingScore::NUMBER_OF_PINS
30
+ end
31
+
32
+ def _out_of_range?(index)
33
+ return true unless @scores[index]
34
+ index >= BowlingScore::NUMBER_OF_FRAME
35
+ end
36
+
37
+ def _rewarded_frame(index)
38
+ index_increment_for_next = _is_strike?(index) ? 1 : 2
39
+ rewarded_score = _rewarded_score(index)
40
+ index_for_next = index + index_increment_for_next
41
+ rewarded_score + _calculate_from_frame(index_for_next)
42
+ end
43
+
44
+ def _unrewarded_frame(index)
45
+ _score_from_frame(index) + _calculate_from_frame(index + 2)
46
+ end
47
+
48
+ def _rewarded_score(index)
49
+ end_index = (index + 2)
50
+ scores = @scores[index..end_index] || []
51
+ scores.reduce(:+) || 0
52
+ end
53
+
54
+ def _score_from_frame(index)
55
+ end_index = (index + 1)
56
+ scores = @scores[index..end_index] || []
57
+ scores.reduce(:+) || 0
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,4 @@
1
+ # Versioning
2
+ module BowlingScore
3
+ VERSION = '0.0.1'
4
+ end
@@ -0,0 +1,10 @@
1
+ require 'bowling_score/version'
2
+ require 'bowling_score/score_calculator'
3
+
4
+ # Bowling Score module defines constants needed fr Bowling Score calculation
5
+ module BowlingScore
6
+ NUMBER_OF_PINS = 10
7
+ NUMBER_OF_STRIKE_REWARD = 2
8
+ NUMBER_OF_SPARE_REWARD = 1
9
+ NUMBER_OF_FRAME = 10
10
+ end
@@ -0,0 +1,215 @@
1
+ require 'spec_helper'
2
+
3
+ describe BowlingScore::ScoreCalculator do
4
+ subject { described_class.new(score_array) }
5
+ let(:score_array) { [rand(11), rand(11), rand(11)] }
6
+
7
+ describe '#initialize' do
8
+ context 'with array of scores' do
9
+ it 'assigns with array of scores' do
10
+ expect(subject.instance_variable_get(:@scores)).to eq score_array
11
+ end
12
+
13
+ context 'with with non-integer character' do
14
+ it 'convert to zero and assigns' do
15
+ params = [1, 2, 'abc', 4]
16
+ new_subject = described_class.new(params)
17
+ expected = [1, 2, 0, 4]
18
+ expect(new_subject.instance_variable_get(:@scores)).to eq expected
19
+ end
20
+ end
21
+
22
+ context 'with with string of integer' do
23
+ it 'convert to integer and assigns with array of scores' do
24
+ params = %w(1 2 3 4)
25
+ new_subject = described_class.new(params)
26
+ expected = [1, 2, 3, 4]
27
+ expect(new_subject.instance_variable_get(:@scores)).to eq expected
28
+ end
29
+ end
30
+
31
+ context 'with array of score mixed' do
32
+ context 'with non-integer character preceeding integer' do
33
+ it 'convert to array with zero for that score and assigns' do
34
+ params = [1, 2, 3, 'abc4', 5]
35
+ new_subject = described_class.new(params)
36
+ expected = [1, 2, 3, 0, 5]
37
+ expect(new_subject.instance_variable_get(:@scores)).to eq expected
38
+ end
39
+ end
40
+
41
+ context 'with integer preceeding non-integer character' do
42
+ it 'convert to array with the integer for that score and assigns' do
43
+ params = [1, 2, 3, '4abc', 5]
44
+ new_subject = described_class.new(params)
45
+ expected = (1..5).to_a
46
+ expect(new_subject.instance_variable_get(:@scores)).to eq expected
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'with string representation of scores' do
53
+ context 'with proper comma separated integer' do
54
+ it 'convert to array and assigns with array of scores' do
55
+ params = '1,2,3,4,5,6'
56
+ new_subject = described_class.new(params)
57
+ expected = (1..6).to_a
58
+ expect(new_subject.instance_variable_get(:@scores)).to eq expected
59
+ end
60
+ end
61
+
62
+ context 'with string of non-integer character' do
63
+ it 'convert to array of zeroes and assigns with array of scores' do
64
+ params = 'abc,%^&'
65
+ new_subject = described_class.new(params)
66
+ expected = [0, 0]
67
+ expect(new_subject.instance_variable_get(:@scores)).to eq expected
68
+ end
69
+ end
70
+
71
+ context 'with string of score mixed' do
72
+ context 'with non-integer character preceeding integer' do
73
+ it 'convert to array with zero for that score and assigns' do
74
+ params = '1,2,3,abc4, 5'
75
+ new_subject = described_class.new(params)
76
+ expected = [1, 2, 3, 0, 5]
77
+ expect(new_subject.instance_variable_get(:@scores)).to eq expected
78
+ end
79
+ end
80
+
81
+ context 'with integer preceeding non-integer character' do
82
+ it 'convert to array with the integer for that score and assigns' do
83
+ params = '1,2,3,4abc, 5'
84
+ new_subject = described_class.new(params)
85
+ expected = (1..5).to_a
86
+ expect(new_subject.instance_variable_get(:@scores)).to eq expected
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ describe '#calculate' do
94
+ context 'with a perfect game of a 12 frames scenario' do
95
+ it 'returns 300' do
96
+ test_array = Array.new(12) { 10 }
97
+ subject.instance_variable_set(:@scores, test_array)
98
+ expect(subject.calculate).to eq 300
99
+ end
100
+ end
101
+
102
+ context 'with a game of zeroes' do
103
+ it 'returns 0' do
104
+ test_array = Array.new(10) { 0 }
105
+ subject.instance_variable_set(:@scores, test_array)
106
+ expect(subject.calculate).to eq 0
107
+ end
108
+ end
109
+
110
+ context 'with a single strike' do
111
+ context 'as the last score' do
112
+ it 'returns sum of all scores' do
113
+ test_array = [1, 1, 10]
114
+ subject.instance_variable_set(:@scores, test_array)
115
+ sum = test_array.reduce(:+)
116
+ expect(subject.calculate).to eq(sum)
117
+ end
118
+ end
119
+
120
+ context 'followed by scores of 2' do
121
+ it 'returns sum of all scores plus 2' do
122
+ test_array = [1, 1, 10, 2]
123
+ subject.instance_variable_set(:@scores, test_array)
124
+ sum = test_array.reduce(:+)
125
+ expect(subject.calculate).to eq(sum + 2)
126
+ end
127
+ end
128
+
129
+ context 'followed by scores of 2 and 3' do
130
+ it 'returns sum of all scores plus 5' do
131
+ test_array = [1, 1, 10, 2, 3]
132
+ subject.instance_variable_set(:@scores, test_array)
133
+ sum = test_array.reduce(:+)
134
+ expect(subject.calculate).to eq(sum + 5)
135
+ end
136
+ end
137
+ end
138
+
139
+ context 'with a double' do
140
+ context 'as the last score' do
141
+ it 'returns sum of all scores plus 10' do
142
+ test_array = [1, 1, 10, 10]
143
+ subject.instance_variable_set(:@scores, test_array)
144
+ sum = test_array.reduce(:+)
145
+ expect(subject.calculate).to eq(sum + 10)
146
+ end
147
+ end
148
+
149
+ context 'followed by scores of 3' do
150
+ it 'returns sum of all scores plus 13 and 3' do
151
+ test_array = [1, 1, 10, 10, 3]
152
+ subject.instance_variable_set(:@scores, test_array)
153
+ sum = test_array.reduce(:+)
154
+ expect(subject.calculate).to eq(sum + 13 + 3)
155
+ end
156
+ end
157
+
158
+ context 'followed by scores of 3 and 4' do
159
+ it 'returns sum of all scores plus 13 and 7' do
160
+ test_array = [1, 1, 10, 10, 3, 4]
161
+ subject.instance_variable_set(:@scores, test_array)
162
+ sum = test_array.reduce(:+)
163
+ expect(subject.calculate).to eq(sum + 13 + 7)
164
+ end
165
+ end
166
+ end
167
+
168
+ context 'with a turkey followed by scores of 4 and 5' do
169
+ it 'returns sum of all scores plus 14 and 9' do
170
+ test_array = [1, 1, 10, 10, 10, 4, 5]
171
+ subject.instance_variable_set(:@scores, test_array)
172
+ sum = test_array.reduce(:+)
173
+ expect(subject.calculate).to eq(sum + 20 + 14 + 9)
174
+ end
175
+ end
176
+
177
+ context 'with a spare' do
178
+ context 'as the last score' do
179
+ it 'returns sum of all scores' do
180
+ test_array = [1, 1, 5, 5]
181
+ subject.instance_variable_set(:@scores, test_array)
182
+ sum = test_array.reduce(:+)
183
+ expect(subject.calculate).to eq(sum)
184
+ end
185
+ end
186
+
187
+ context 'followed by score of 4' do
188
+ it 'returns sum of all scores plus 4' do
189
+ test_array = [1, 1, 5, 5, 4]
190
+ subject.instance_variable_set(:@scores, test_array)
191
+ sum = test_array.reduce(:+)
192
+ expect(subject.calculate).to eq(sum + 4)
193
+ end
194
+ end
195
+ end
196
+
197
+ context 'with a spare followed by a strike, then 3 and 4' do
198
+ it 'returns sum of all scores plus 10, 3 and 4' do
199
+ test_array = [1, 1, 5, 5, 10, 3, 4]
200
+ subject.instance_variable_set(:@scores, test_array)
201
+ sum = test_array.reduce(:+)
202
+ expect(subject.calculate).to eq(sum + 10 + 3 + 4)
203
+ end
204
+ end
205
+
206
+ context 'with a strike followed by a spare of 4 and 6, then 3 and 4' do
207
+ it 'returns sum of all scores plus 4, 6 and 3' do
208
+ test_array = [1, 1, 10, 4, 6, 3, 4]
209
+ subject.instance_variable_set(:@scores, test_array)
210
+ sum = test_array.reduce(:+)
211
+ expect(subject.calculate).to eq(sum + 4 + 6 + 3)
212
+ end
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe BowlingScore do
4
+ describe 'Constant NUMBER_OF_PINS' do
5
+ it 'returns 10' do
6
+ expect(described_class::NUMBER_OF_PINS).to eq 10
7
+ end
8
+ end
9
+
10
+ describe 'Constant NUMBER_OF_STRIKE_REWARD' do
11
+ it 'returns 2' do
12
+ expect(described_class::NUMBER_OF_STRIKE_REWARD).to eq 2
13
+ end
14
+ end
15
+
16
+ describe 'Constant NUMBER_OF_SPARE_REWARD' do
17
+ it 'returns 1' do
18
+ expect(described_class::NUMBER_OF_SPARE_REWARD).to eq 1
19
+ end
20
+ end
21
+
22
+ describe 'Constant NUMBER_OF_FRAME' do
23
+ it 'returns 10' do
24
+ expect(described_class::NUMBER_OF_FRAME).to eq 10
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,11 @@
1
+ require 'bowling_score'
2
+
3
+ RSpec.configure do |config|
4
+ config.expect_with :rspec do |expectations|
5
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
6
+ end
7
+
8
+ config.mock_with :rspec do |mocks|
9
+ mocks.verify_partial_doubles = true
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bowling_score
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ian Choi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: |-
42
+ Bowling score calculator support strike and spare rules
43
+ of rewarding. Taking string as scores.
44
+ email:
45
+ - achiinto@gmail.com
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - ".gitignore"
51
+ - ".rspec"
52
+ - Gemfile
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - bowling_score.gemspec
57
+ - lib/bowling_score.rb
58
+ - lib/bowling_score/score_calculator.rb
59
+ - lib/bowling_score/version.rb
60
+ - spec/bowling_score/score_calculator_spec.rb
61
+ - spec/bowling_score_spec.rb
62
+ - spec/spec_helper.rb
63
+ homepage: ''
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.4.5
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Bowling score calculator
87
+ test_files:
88
+ - spec/bowling_score/score_calculator_spec.rb
89
+ - spec/bowling_score_spec.rb
90
+ - spec/spec_helper.rb
91
+ has_rdoc: