bowlero 0.1.3 → 0.1.5

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
  SHA256:
3
- metadata.gz: c01e56b4b39c0d094c6f67191df90a91679d2b8dd30d3026f22e8fc5cd0fb6ce
4
- data.tar.gz: 24fa7a8b3b43670c4d42f9ed3713aa75c3a7b35105502255a9d38b0560d7cf8f
3
+ metadata.gz: 4866b12e70993cfa04847186591671976562d28996a975b01d8171d6bc534577
4
+ data.tar.gz: 9115b09508a42b9d18054f434b6486a56f68a216e2de31b50619ac93f0152045
5
5
  SHA512:
6
- metadata.gz: 72653bcd54b1f2372b7d16d4316b1e42f6c8fc707732391aae4acdd87837dc54057458b42d96280fa1245c53e0f8a20dafa3479d2dfaff0b951f1c58fa261c13
7
- data.tar.gz: 33714615f2fc2e34d01c57057ef753064498b438e660e257c3e4e2dcc4eff63378c7fd520a5c1a2e5b75ec3c390c7f300d56450646ecd608d1a55986f90a3047
6
+ metadata.gz: 2f5b78cec0d2c5843d3dc685d92c8265cc562d08b9698e12370c6ed80f5c9b115a85856cbdcd9e52885c6d0bba5f5ebe659c1766ea65f0b4a00d614ec0eb9aca
7
+ data.tar.gz: 657462265218e270f2f37211a755aeab67bdb61f570357b141249e70014a08df681427bcc8daf99eaacee72aa6385e4a27b9a94402044903eaf23d956fb444a4
data/bowlero-0.1.3.gem ADDED
Binary file
@@ -0,0 +1,393 @@
1
+ module Bowlero
2
+ class CLI
3
+ PUN_NAMES = [
4
+ 'Pin Diesel', 'Bowl Job', "Livin' on a Spare", 'Alley McBowl',
5
+ 'Split Happens', 'Gutterball Guru', 'The Pincredible Hulk',
6
+ 'Strike Tyson', 'Bowliver Twist', 'Rolling Thunder'
7
+ ]
8
+
9
+ def self.start
10
+ def clear_screen
11
+ system('clear') || system('cls')
12
+ end
13
+
14
+ def prompt(message)
15
+ print "#{message} "
16
+ gets.chomp
17
+ end
18
+
19
+ def main_menu
20
+ loop do
21
+ clear_screen
22
+ puts '🎳 Welcome to Bowlero! 🎳'
23
+ puts '1. Start Game'
24
+ puts '2. Exit'
25
+ print 'Choose an option: '
26
+ choice = gets.chomp.strip
27
+ case choice
28
+ when '1'
29
+ start_game
30
+ when '2'
31
+ puts 'Thanks for playing Bowlero!'
32
+ exit(0)
33
+ else
34
+ puts 'Invalid option. Press Enter to try again.'
35
+ gets
36
+ end
37
+ end
38
+ end
39
+
40
+ def start_game
41
+ clear_screen
42
+ default_name = PUN_NAMES.sample
43
+ name = prompt("Enter your player name [#{default_name}]:")
44
+ name = default_name if name.strip.empty?
45
+ puts "\nWelcome, #{name}! Let's bowl a full game."
46
+
47
+ frames = []
48
+ 10.times do |frame_num|
49
+ puts "\n--- Frame #{frame_num + 1} ---"
50
+ frame = Bowlero::Frame.new(frame_number: frame_num + 1)
51
+ if frame_num < 9
52
+ # Regular frames (1-9)
53
+ strike_die = Bowlero::Dice.roll_strike_die
54
+ split_die = Bowlero::Dice.roll_split_die
55
+ if strike_die == :strike
56
+ puts "🎳 STRIKE! You knocked down all 10 pins on the first roll!"
57
+ frame.result = :strike
58
+ frame.first_roll = 10
59
+ frame.second_roll = 0
60
+ frame.pins = 10
61
+ frames << frame
62
+ next
63
+ end
64
+ # Not a strike, so sum pins
65
+ if split_die == :split
66
+ split_value = 6
67
+ total_pins = strike_die + split_value
68
+ frame.split = true
69
+ puts "You knocked down #{strike_die} pins and left a SPLIT! (Split worth 6, Total: #{total_pins} pins)"
70
+ else
71
+ split_value = split_die
72
+ total_pins = strike_die + split_value
73
+ frame.split = false
74
+ puts "You knocked down #{strike_die} and #{split_die} pins (Total: #{total_pins})"
75
+ end
76
+ frame.first_roll = total_pins > 10 ? 10 : total_pins
77
+ if total_pins >= 10
78
+ puts "That's a STRIKE by pin count!"
79
+ frame.result = :strike
80
+ frame.second_roll = 0
81
+ frame.pins = 10
82
+ else
83
+ # Second roll
84
+ if split_die == :split
85
+ split_res = Bowlero::Dice.roll_split_resolution_die
86
+ frame.split_converted = (split_res == :spare)
87
+ if split_res == :spare
88
+ puts "You converted the split for a SPARE!"
89
+ frame.result = :spare
90
+ frame.second_roll = 10 - frame.first_roll
91
+ frame.pins = 10
92
+ else
93
+ puts "Open frame. Some pins left standing."
94
+ frame.result = :open
95
+ frame.second_roll = 0
96
+ frame.pins = frame.first_roll
97
+ end
98
+ else
99
+ spare_res = Bowlero::Dice.roll_spare_resolution_die
100
+ if spare_res == :spare
101
+ puts "You picked up the spare!"
102
+ frame.result = :spare
103
+ frame.second_roll = 10 - frame.first_roll
104
+ frame.pins = 10
105
+ else
106
+ puts "Open frame. Some pins left standing."
107
+ frame.result = :open
108
+ frame.second_roll = 0
109
+ frame.pins = frame.first_roll
110
+ end
111
+ end
112
+ end
113
+ frames << frame
114
+ else
115
+ # 10th frame special logic
116
+ puts "10th frame! You can get up to 3 rolls if you strike or spare."
117
+ # First roll
118
+ strike_die = Bowlero::Dice.roll_strike_die
119
+ split_die = Bowlero::Dice.roll_split_die
120
+ if strike_die == :strike
121
+ puts "🎳 STRIKE! You knocked down all 10 pins on the first roll!"
122
+ frame.first_roll = 10
123
+ frame.result = :strike
124
+ # Second roll (bonus)
125
+ strike_die2 = Bowlero::Dice.roll_strike_die
126
+ split_die2 = Bowlero::Dice.roll_split_die
127
+ if strike_die2 == :strike
128
+ puts "🎳 STRIKE! Second roll in 10th frame is a strike!"
129
+ frame.second_roll = 10
130
+ else
131
+ if split_die2 == :split
132
+ split_value2 = 6
133
+ total_pins2 = strike_die2 + split_value2
134
+ puts "You knocked down #{strike_die2} pins and left a SPLIT! (Split worth 6, Total: #{total_pins2} pins)"
135
+ frame.second_roll = total_pins2 > 10 ? 10 : total_pins2
136
+ else
137
+ split_value2 = split_die2
138
+ total_pins2 = strike_die2 + split_value2
139
+ puts "You knocked down #{strike_die2} and #{split_die2} pins (Total: #{total_pins2})"
140
+ frame.second_roll = total_pins2 > 10 ? 10 : total_pins2
141
+ end
142
+ end
143
+ # Third roll (bonus)
144
+ strike_die3 = Bowlero::Dice.roll_strike_die
145
+ split_die3 = Bowlero::Dice.roll_split_die
146
+ if strike_die3 == :strike
147
+ puts "🎳 STRIKE! Third roll in 10th frame is a strike!"
148
+ frame.third_roll = 10
149
+ else
150
+ if split_die3 == :split
151
+ split_value3 = 6
152
+ total_pins3 = strike_die3 + split_value3
153
+ puts "You knocked down #{strike_die3} pins and left a SPLIT! (Split worth 6, Total: #{total_pins3} pins)"
154
+ frame.third_roll = total_pins3 > 10 ? 10 : total_pins3
155
+ else
156
+ split_value3 = split_die3
157
+ total_pins3 = strike_die3 + split_value3
158
+ puts "You knocked down #{strike_die3} and #{split_die3} pins (Total: #{total_pins3})"
159
+ frame.third_roll = total_pins3 > 10 ? 10 : total_pins3
160
+ end
161
+ end
162
+ else
163
+ # Not a strike on first roll
164
+ if split_die == :split
165
+ split_value = 6
166
+ total_pins = strike_die + split_value
167
+ puts "You knocked down #{strike_die} pins and left a SPLIT! (Split worth 6, Total: #{total_pins} pins)"
168
+ frame.split = true
169
+ else
170
+ split_value = split_die
171
+ total_pins = strike_die + split_value
172
+ puts "You knocked down #{strike_die} and #{split_die} pins (Total: #{total_pins})"
173
+ frame.split = false
174
+ end
175
+ frame.first_roll = total_pins > 10 ? 10 : total_pins
176
+ # Second roll
177
+ if total_pins >= 10
178
+ puts "That's a STRIKE by pin count!"
179
+ frame.result = :strike
180
+ # Two more rolls
181
+ strike_die2 = Bowlero::Dice.roll_strike_die
182
+ split_die2 = Bowlero::Dice.roll_split_die
183
+ if strike_die2 == :strike
184
+ puts "🎳 STRIKE! Second roll in 10th frame is a strike!"
185
+ frame.second_roll = 10
186
+ else
187
+ if split_die2 == :split
188
+ split_value2 = 6
189
+ total_pins2 = strike_die2 + split_value2
190
+ puts "You knocked down #{strike_die2} pins and left a SPLIT! (Split worth 6, Total: #{total_pins2} pins)"
191
+ frame.second_roll = total_pins2 > 10 ? 10 : total_pins2
192
+ else
193
+ split_value2 = split_die2
194
+ total_pins2 = strike_die2 + split_value2
195
+ puts "You knocked down #{strike_die2} and #{split_die2} pins (Total: #{total_pins2})"
196
+ frame.second_roll = total_pins2 > 10 ? 10 : total_pins2
197
+ end
198
+ end
199
+ # Third roll
200
+ strike_die3 = Bowlero::Dice.roll_strike_die
201
+ split_die3 = Bowlero::Dice.roll_split_die
202
+ if strike_die3 == :strike
203
+ puts "🎳 STRIKE! Third roll in 10th frame is a strike!"
204
+ frame.third_roll = 10
205
+ else
206
+ if split_die3 == :split
207
+ split_value3 = 6
208
+ total_pins3 = strike_die3 + split_value3
209
+ puts "You knocked down #{strike_die3} pins and left a SPLIT! (Split worth 6, Total: #{total_pins3} pins)"
210
+ frame.third_roll = total_pins3 > 10 ? 10 : total_pins3
211
+ else
212
+ split_value3 = split_die3
213
+ total_pins3 = strike_die3 + split_value3
214
+ puts "You knocked down #{strike_die3} and #{split_die3} pins (Total: #{total_pins3})"
215
+ frame.third_roll = total_pins3 > 10 ? 10 : total_pins3
216
+ end
217
+ end
218
+ else
219
+ # Not a strike by pin count, so check for split or spare
220
+ if split_die == :split
221
+ split_res = Bowlero::Dice.roll_split_resolution_die
222
+ if split_res == :spare
223
+ puts "You converted the split for a SPARE!"
224
+ frame.result = :spare
225
+ frame.second_roll = 10 - frame.first_roll
226
+ # Third roll (bonus)
227
+ strike_die3 = Bowlero::Dice.roll_strike_die
228
+ split_die3 = Bowlero::Dice.roll_split_die
229
+ if strike_die3 == :strike
230
+ puts "🎳 STRIKE! Third roll in 10th frame is a strike!"
231
+ frame.third_roll = 10
232
+ else
233
+ if split_die3 == :split
234
+ split_value3 = 6
235
+ total_pins3 = strike_die3 + split_value3
236
+ puts "You knocked down #{strike_die3} pins and left a SPLIT! (Split worth 6, Total: #{total_pins3} pins)"
237
+ frame.third_roll = total_pins3 > 10 ? 10 : total_pins3
238
+ else
239
+ split_value3 = split_die3
240
+ total_pins3 = strike_die3 + split_value3
241
+ puts "You knocked down #{strike_die3} and #{split_die3} pins (Total: #{total_pins3})"
242
+ frame.third_roll = total_pins3 > 10 ? 10 : total_pins3
243
+ end
244
+ end
245
+ else
246
+ puts "Open frame. Some pins left standing."
247
+ frame.result = :open
248
+ frame.second_roll = 0
249
+ frame.third_roll = 0
250
+ end
251
+ else
252
+ spare_res = Bowlero::Dice.roll_spare_resolution_die
253
+ if spare_res == :spare
254
+ puts "You picked up the spare!"
255
+ frame.result = :spare
256
+ frame.second_roll = 10 - frame.first_roll
257
+ # Third roll (bonus)
258
+ strike_die3 = Bowlero::Dice.roll_strike_die
259
+ split_die3 = Bowlero::Dice.roll_split_die
260
+ if strike_die3 == :strike
261
+ puts "🎳 STRIKE! Third roll in 10th frame is a strike!"
262
+ frame.third_roll = 10
263
+ else
264
+ if split_die3 == :split
265
+ split_value3 = 6
266
+ total_pins3 = strike_die3 + split_value3
267
+ puts "You knocked down #{strike_die3} pins and left a SPLIT! (Split worth 6, Total: #{total_pins3} pins)"
268
+ frame.third_roll = total_pins3 > 10 ? 10 : total_pins3
269
+ else
270
+ split_value3 = split_die3
271
+ total_pins3 = strike_die3 + split_value3
272
+ puts "You knocked down #{strike_die3} and #{split_die3} pins (Total: #{total_pins3})"
273
+ frame.third_roll = total_pins3 > 10 ? 10 : total_pins3
274
+ end
275
+ end
276
+ else
277
+ puts "Open frame. Some pins left standing."
278
+ frame.result = :open
279
+ frame.second_roll = 0
280
+ frame.third_roll = 0
281
+ end
282
+ end
283
+ end
284
+ end
285
+ # For 10th frame, pins = sum of all rolls
286
+ frame.pins = (frame.first_roll || 0) + (frame.second_roll || 0) + (frame.third_roll || 0)
287
+ frames << frame
288
+ end
289
+ end
290
+
291
+ # --- Scoring pass ---
292
+ def next_rolls(frames, idx, count)
293
+ rolls = []
294
+ i = idx + 1
295
+ while rolls.size < count && i < frames.size
296
+ f = frames[i]
297
+ rolls << f.first_roll if rolls.size < count
298
+ rolls << f.second_roll if rolls.size < count
299
+ i += 1
300
+ end
301
+ rolls[0, count]
302
+ end
303
+
304
+ total_score = 0
305
+ frames.each_with_index do |f, i|
306
+ if i == 9
307
+ # 10th frame: just sum the rolls
308
+ f.score = (f.first_roll || 0) + (f.second_roll || 0) + (f.third_roll || 0)
309
+ total_score += f.score
310
+ f.score = total_score
311
+ elsif f.result == :strike
312
+ bonus_rolls = next_rolls(frames, i, 2)
313
+ f.score = 10 + bonus_rolls.sum
314
+ total_score += f.score
315
+ f.score = total_score
316
+ elsif f.result == :spare
317
+ bonus_rolls = next_rolls(frames, i, 1)
318
+ f.score = 10 + bonus_rolls.sum
319
+ total_score += f.score
320
+ f.score = total_score
321
+ else
322
+ f.score = f.first_roll + f.second_roll
323
+ total_score += f.score
324
+ f.score = total_score
325
+ end
326
+ end
327
+
328
+ def print_scorecard(frames)
329
+ # Frame header
330
+ puts '+---' * 10 + '+'
331
+ print '|'
332
+ (1..10).each { |n| print "%2s |" % n }
333
+ puts
334
+ puts '+-+-' * 10 + '+'
335
+
336
+ # Rolls row
337
+ print '|'
338
+ frames.each_with_index do |f, i|
339
+ if i == 9
340
+ # 10th frame: show up to 3 rolls
341
+ r1 = f.first_roll == 10 ? 'X' : f.first_roll.to_s
342
+ r2 = f.second_roll == 10 ? 'X' : (f.result == :spare ? '/' : f.second_roll.to_s)
343
+ r3 = f.third_roll == 10 ? 'X' : (f.third_roll.nil? ? ' ' : f.third_roll.to_s)
344
+ print "%s|%s|%s|" % [r1, r2, r3]
345
+ else
346
+ r1 = r2 = ' '
347
+ if f.result == :strike
348
+ r1 = 'X'
349
+ r2 = ' '
350
+ elsif f.result == :spare
351
+ r1 = f.first_roll == 0 ? '-' : f.first_roll.to_s
352
+ r2 = '/'
353
+ elsif f.split
354
+ r1 = f.first_roll == 0 ? '-' : f.first_roll.to_s
355
+ r2 = 'S'
356
+ else
357
+ r1 = f.first_roll == 0 ? '-' : f.first_roll.to_s
358
+ r2 = f.second_roll == 0 ? '-' : f.second_roll.to_s
359
+ end
360
+ print "%s|%s|" % [r1, r2]
361
+ end
362
+ end
363
+ puts
364
+ puts '+---' * 10 + '+'
365
+
366
+ # Scores row
367
+ print '|'
368
+ frames.each { |f| print "%3s|" % f.score }
369
+ puts
370
+ puts '+---' * 10 + '+'
371
+ end
372
+
373
+ puts "\n--- Game Summary for #{name} ---"
374
+ print_scorecard(frames)
375
+ frames.each do |f|
376
+ case f.result
377
+ when :strike
378
+ puts "Frame #{f.frame_number}: STRIKE! (10 pins) | Running Score: #{f.score}"
379
+ when :spare
380
+ puts "Frame #{f.frame_number}: SPARE! (#{f.pins} pins) | Running Score: #{f.score}"
381
+ else
382
+ puts "Frame #{f.frame_number}: Open frame (#{f.pins} pins) | Running Score: #{f.score}"
383
+ end
384
+ end
385
+ puts "\nFinal Score: #{frames.last.score}"
386
+ puts "\n[Press Enter to return to menu]"
387
+ gets
388
+ end
389
+
390
+ main_menu
391
+ end
392
+ end
393
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bowlero
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.5"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bowlero
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Benner
@@ -26,8 +26,10 @@ files:
26
26
  - README.md
27
27
  - Rakefile
28
28
  - bowlero-0.1.0.gem
29
+ - bowlero-0.1.3.gem
29
30
  - exe/bowlero
30
31
  - lib/bowlero.rb
32
+ - lib/bowlero/cli.rb
31
33
  - lib/bowlero/dice.rb
32
34
  - lib/bowlero/frame.rb
33
35
  - lib/bowlero/version.rb