#(0 0 10 8 2 10 10 10 5 3 8 2 10 10 10 10) bowlingScore " => 201 "
まずは Haskell 版を直訳ぎみにして、それからヒネリを入れてみよう…と思ったのですが、もとがあまりにシンプルで代替え案が思いつかなかったのでそのままです。あしからず。
下の定義はファイルイン用コードなので、コピーして Squeak システムのどこか適当な場所にペーストした後、あらためて全体を選択して fileIn selection (alt/cmd + shift + g) とするなどの操作で読み込めます。テストは open... → SUnit Test Runner から ArrayBowlingScoreTest を探して選択 → Run One してください。
'From Squeakland 3.8-05 of 7 September 2005 [latest update: #527]'! !Array methodsFor: 'math functions' stamp: 'sumim 11/21/2006'! bowlingScore self isEmpty ifTrue: [^ 0]. self size = 1 ifTrue: [^ self first]. self size <= 3 ifTrue: [^ self sum]. self first = 10 ifTrue: [^ (self first: 3) sum + self allButFirst bowlingScore]. self first + self second = 10 ifTrue: [^ (self first: 3) sum + (self allButFirst: 2) bowlingScore]. ^ self first + self second + (self allButFirst: 2) bowlingScore ! ! TestCase subclass: #ArrayBowlingScoreTest instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Collections-Arrayed-Tests'! !ArrayBowlingScoreTest methodsFor: 'tests' stamp: 'sumim 11/21/2006'! test1 self assert: #(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) bowlingScore = 0 ! ! !ArrayBowlingScoreTest methodsFor: 'tests' stamp: 'sumim 11/21/2006'! test2 self assert: (Array new: 12 withAll: 10) bowlingScore = 300 ! ! !ArrayBowlingScoreTest methodsFor: 'tests' stamp: 'sumim 11/21/2006'! test3 self assert: (#(10 5 5), (Array new: 17 withAll: 0)) bowlingScore = 30 ! ! !ArrayBowlingScoreTest methodsFor: 'tests' stamp: 'sumim 11/21/2006'! test4 self assert: (Array new: 20 withAll: 3) bowlingScore = 60 ! !
おまけ
Ruby にも Smalltalk の #sum、#first、#first:、#second、#allButFirst、#allButFirst: を定義して直訳気味に。
[0,0,10,8,2,10,10,10,5,3,8,2,10,10,10,10].bowling_score #=> 201
class Array def bowling_score return 0 if empty? return first if size == 1 return sum if size <= 3 return first(3).sum + all_but_first.bowling_score if first == 10 return first(3).sum + all_but_first(2).bowling_score if first + second == 10 first + second + all_but_first(2).bowling_score end def sum inject(0) { |s,e| s+e } end def first(n=1) if n == 1 self[0] else self[0, n] end end def second self[1] end def all_but_first(n=1) self[n, size - n + 1] end end
id:sumim:20061124:p1 に続く。