Forum: Ruby Bowling Scores (#181)

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Matthew M. (Guest)
on 2008-10-24 18:27
(Received via mailing list)
Apologies for not having the Long Division quiz summary done yet. It
will come sometime today or tomorrow. Meanwhile, I have the next quiz
ready...

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Q. 2:

1.  Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message.

2.  Support Ruby Q. 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Q. 2. Until then,
please visit the temporary website at

   <http://splatbang.com/rubyquiz/>.

3.  Enjoy!

Suggestion:  A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby T. follow the discussion.  Please reply to
the original quiz message, if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## Bowling Scores (#181)


Whether it is real or on the Wii, bowling is a fun game. (Okay, for
the sake of the quiz, let's assume it's a fun game.) But I've known
folks who just don't understand [how to score properly][1]. They can
count pins knocked down, and know that getting all ten pins in one
roll is good, but they still can't keep score.

Your task this week is to tally scores for these people. The input
will be the player's name and the number of pins felled from each
roll. For example:

     ruby bowling_scores.rb John 6 2 7 1 10 9 0 8 2 10 10 3 5 7 2 5 5 8

Your should tally the per-frame scores and generate output in table
form, such as:

     John's final score: 140

     Frame     Roll  Roll    Score
        1        6     2        8
        2        7     1       16
        3        X             35
        4        9     -       44
        5        8     /       64
        6        X             87
        7        X            105
        8        3     5      113
        9        7     2      122
       10        5     /      140
        *        8


Note that you should make use of typical bowling symbols: `X` for a
strike, `/` for a spare, and `-` for zero. Also, if extra balls were
thrown at the end (to supplement a strike or spare in the final
frame), list those as frame `*` like the above, but without a score.

Extra credit: Generate ascii or graphical output that looks more like
the traditional bowling score form, which can be seen on [this page][1].


[1]: http://www.bowling2u.com/trivia/game/scoring.asp
Andrea F. (Guest)
on 2008-10-26 17:34
(Received via mailing list)
Matthew M. ha scritto:
> ## Bowling Scores (#181)

Hi all,

here's my solution:

http://github.com/remogatto/quizzes/tree/master/18...

Regards,
Andrea
Kristian Elof Sørensen (Guest)
on 2008-10-26 18:03
(Received via mailing list)
fre, 24 10 2008 kl. 23:25 +0900, skrev Matthew M.:
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> ## Bowling Scores (#181)

# a simple no-frills tail-recursive implementation
class Bowling
  def initialize
    playBowling(ARGV[0], ARGV[1..ARGV.length].collect { |n| n.to_i })
  end
  def playBowling(player, pins)
    printf("\nFrame   Roll Roll   Score\n")
    printf("\n%s's final score: %d\n\n", player, doFrame(pins))
  end
  def doFrame(pins, frame = 1, subtotal = 0)
    dSubtotal = 0
    if pins.length > 0
      if frame > 10
  printFrame("*", pins[0], pins[1], "")
  pins = []
      elsif pins[0] == 10
  dSubtotal = + pins[0] + pins[1] + pins[2]
  printFrame(frame, "X", " ", subtotal + dSubtotal)
  pins = pins[1..pins.length]
      elsif pins[0] + pins[1] == 10
  dSubtotal = pins[0] + pins[1] + pins[2]
  printFrame(frame, pins[0], "/", subtotal + dSubtotal)
  pins = pins[2..pins.length]
      else
  dSubtotal = pins[0] + pins[1]
  printFrame(frame, pins[0], pins[1], subtotal + dSubtotal)
  pins = pins[2..pins.length]
      end
      doFrame(pins, frame + 1, subtotal + dSubtotal)
    else
      subtotal
    end
  end
  def printFrame(frameNr, ball0, ball1, subtotal)
    printf("  %2s      %s    %s     %3s\n", frameNr, ball0, ball1,
subtotal)
  end
end

Bowling.new() if $0 == __FILE__
Ken B. (Guest)
on 2008-10-26 19:10
(Received via mailing list)
On Fri, 24 Oct 2008 09:25:45 -0500, Matthew M. wrote:

>
> original quiz message, if you can.
> good, but they still can't keep score.
>      John's final score: 140
>         9        7     2      122
> the traditional bowling score form, which can be seen on [this page][1].
>
>
> [1]: http://www.bowling2u.com/trivia/game/scoring.asp

#!/usr/bin/env ruby
#Requires Ruby 1.8.7

class Fixnum
  def to_bowl
    return '-' if self==0
    return 'X' if self==10
    return self.to_s
  end
end

class Array
  def strike?
    self[0]==10
  end
  def spare?
    self[0]+self[1]==10
  end
end

module Enumerable
  #each cons is almost what I want, but it won't generate partial cons
at the end
  def mycons n
    result=[]
    each_with_index do |f,i|
      result << self[i,n]
    end
    result
  end
end

ARGV.map!(&:to_i)
fail if ARGV.any?{|x| x>10}
frames=ARGV.mycons(3)
frames.delete_at(-1)

frames.each_with_index do |f,i|
  frames[i+1]=nil if f and not f.strike?
end
frames.compact!
totals=frames.inject([]) do |h,frame|
  last = h[-1] || 0
  frame.delete_at(2) unless frame.spare? or frame.strike?
  h+[last+frame.inject(&:+)]
end
printf "%8s%8s%8s%8s\n", "Frame", "Roll", "Roll", "Score"
frames.each_with_index do |f,i|
  spare='/' if f[0]+f[1]==10
  printf "%8s%8s%8s%8s\n", i+1, f[0].to_bowl, (spare or f[1].to_bowl
unless f.strike?), totals[i]
  if i==9 and f.spare?
    printf "%8s%8s\n", '*', f[2].to_bowl
  elsif i==9 and f.strike?
    printf "%8s%8s%8s\n", '*', f[1].to_bowl, f[2].to_bowl
  end
end
Sandro P. (Guest)
on 2008-10-27 01:28
(Received via mailing list)
Here there's my attempt:


=== CODE START ===

class Array
  def sum; self.inject{|a,b| a+b}; end
end

def get_points (shot,next_shots)
  return shot.sum + (
    # strike
    if shot.first == 10
      next_shots.flatten[0..1].sum
    # spare
    elsif shot.sum == 10
      next_shots.first.first
    # normal
    else
      0
    end
  )
end

def symbols(score,sep)
  return "X#{sep}" if score.first == 10
  return "#{score[0]}#{sep}/" if score.sum == 10
  return "#{score[0]}#{sep}#{score[1]}"
end

name, score, points = ARGV.first, ARGV[1..-1].join(" "), []
raise "Usage: 'ruby 181_bowling_score.rb [name] [scores]'" if name.nil?
or
score.to_a.empty?

score = score.scan(/10|\d+\s*\d*/).collect{|e| e.split(" ").map!{|e|
e.to_i}}
score.each_with_index { |s,i| points[i] = get_points(s,score[i+1..-1]) }

puts "#{name}'s final score: #{points[0..9].sum}";
puts "Frame\tRoll\tRoll\tScore\t"
score.each_with_index do |s,i|
  puts "#{i+1}\t#{symbols(s,"\t")}\t#{(i<10) ? points[0..i].sum : ''}"
end


=== CODE END ===
Sandro P. (Guest)
on 2008-10-27 01:31
(Received via mailing list)
Sorry, I forgot to translate zeros into -, here's the fixxed version:



=== CODE START (FIX) ===


=begin


## Bowling Scores (#181)


Whether it is real or on the Wii, bowling is a fun game. (Okay, for the
sake
of the quiz, let's assume it's a fun game.) But I've known folks who
just
don't understand [how to score properly][1]. They can count pins knocked
down, and know that getting all ten pins in one roll is good, but they
still
can't keep score.

Your task this week is to tally scores for these people. The input will
be
the player's name and the number of pins felled from each roll. For
example:

   ruby bowling_scores.rb John 6 2 7 1 10 9 0 8 2 10 10 3 5 7 2 5 5 8

Your should tally the per-frame scores and generate output in table
form,
such as:

   John's final score: 140

   Frame     Roll  Roll    Score
      1        6     2        8
      2        7     1       16
      3        X             35
      4        9     -       44
      5        8     /       64
      6        X             87
      7        X            105
      8        3     5      113
      9        7     2      122
     10        5     /      140
      *        8


Note that you should make use of typical bowling symbols: `X` for a
strike,
`/` for a spare, and `-` for zero. Also, if extra balls were thrown at
the
end (to supplement a strike or spare in the final frame), list those as
frame `*` like the above, but without a score.

Extra credit: Generate ascii or graphical output that looks more like
the
traditional bowling score form, which can be seen on [this page][1].


[1]: http://www.bowling2u.com/trivia/game/scoring.asp



=end

class Array
  def sum; self.inject{|a,b| a+b}; end
end

def get_points (shot,next_shots)
  return shot.sum + (
    # strike
    if shot.first == 10
      next_shots.flatten[0..1].sum
    # spare
    elsif shot.sum == 10
      next_shots.first.first
    # normal
    else
      0
    end
  )
end

def symbols(score,sep)
  return "X#{sep}" if score.first == 10
  return (score.sum == 10 ? "#{score[0]}#{sep}/" :
"#{score[0]}#{sep}#{score[1]}").gsub("0","-")
end

name, score, points = ARGV.first, ARGV[1..-1].join(" "), []
raise "Usage: 'ruby 181_bowling_score.rb [name] [scores]'" if name.nil?
or
score.to_a.empty?

score = score.scan(/10|\d+\s*\d*/).collect{|e| e.split(" ").map!{|e|
e.to_i}}
score.each_with_index { |s,i| points[i] = get_points(s,score[i+1..-1]) }

puts "#{name}'s final score: #{points[0..9].sum}";
puts "Frame\tRoll\tRoll\tScore\t"
score.each_with_index do |s,i|
  puts "#{i+1}\t#{symbols(s,"\t")}\t#{(i<10) ? points[0..i].sum : ''}"
end




=== CODE END (FIX) ===








On Sun, Oct 26, 2008 at 11:25 PM, Sandro P. <
James C. (Guest)
on 2008-10-27 14:22
(Received via mailing list)
>       8        3     5      113
>       9        7     2      122
>      10        5     /      140
>       *        8
>


Quick and dirty solution. Should really be able to factor this into a
single
loop but parts of it might end up getting messy.

http://gist.github.com/20087
Douglas S. (Guest)
on 2008-10-27 15:42
(Received via mailing list)
My try up here:

http://www.pastie.org/301342

-Doug Seifert
Brian C. (Guest)
on 2008-10-27 18:16
# Quick and dirty

name = ARGV.shift
ARGV.map! { |e| Integer(e) }
table, score = "", 0
CHARS="-123456789X"
(1..10).each do |frame|
  line = [CHARS[r1 = ARGV.shift,1]]
  if r1 == 10
    score += r1 + ARGV[0] + ARGV[1]
  else
    line << CHARS[r2 = ARGV.shift,1]
    score += (sum = r1 + r2)
    if sum == 10
      score += ARGV[0]
      line[1] = "/"
    end
  end
  table << sprintf(" %2s         %s     %1s      %3d\n",
                   frame, line[0], line[1], score)
end
while r = ARGV.shift
  table << sprintf(" %2s         %s\n", "*", CHARS[r,1])
end
puts <<EOF
#{name}'s final score: #{score}

Frame     Roll  Roll    Score
#{table}
EOF
Matthew M. (Guest)
on 2008-10-30 21:40
(Received via mailing list)
Sorry, behind schedule again, summary coming tomorrow.
This topic is locked and can not be replied to.