bowlero 0.1.3 → 0.1.4

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