Language detail: Smalltalk
|
number of '+' ratings |
contribution for coverage |
Unsolved challenges
codes
Squeak Smalltalk で。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | | str map up down left right pos |
str := 'doukaku'.
up := (down := 1 @ 0) negated.
left := (right := 0 @ 1) negated.
map := Matrix new: str size * 3 + 1 element: Character space.
pos := 1 @ str size + right.
{right. down. right. down. left. down. left. up. left. up. right. up} do: [:direction |
str do: [:chr | map at: pos x at: pos y put: chr. pos := pos + direction]].
World findATranscript: nil.
(1 to: map rowCount) do: [:nrow |
Transcript cr; show: ('', (map atRow: nrow)) withoutTrailingBlanks]
|
Squeak Smalltalk で。つめることができる組み合わせを列挙させてみました。ブロックは画素で表現し、4×4の領域を塗りつぶせる配置があるかで判断しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | | blocks extent rec results |
blocks := {
Form extent: 4@1 fromArray: #(2r1111e28) offset: nil.
Form extent: 2@2 fromArray: #(2r11e30 2r11e30) offset: nil.
Form extent: 3@2 fromArray: #(2r111e29 2r010e29) offset: nil.
Form extent: 3@2 fromArray: #(2r111e29 2r100e29) offset: nil.
Form extent: 3@2 fromArray: #(2r110e29 2r011e29) offset: nil}.
extent := 4@4.
blocks := blocks collect: [:ori |
| specs |
specs := Set new.
#(0 90 180 270) do: [:angle |
| rot |
rot := (ori rotateBy: angle) trimBordersOfColor: Color white.
specs add: {rot extent. rot bits}.
rot := rot flipBy: #horizontal centerAt: 0@0.
specs add: {rot extent. rot bits}].
specs collect: [:spec | Form extent: spec first depth: 1 bits: spec second]].
results := Set new.
(1 to: 5) asDigitsToPower: 4 do: [:comb |
comb isSorted ifTrue: [
| box |
comb printString displayAt: 0@0.
box := Form extent: extent.
rec := nil.
rec := [:prevBox :rest |
| trials currBox |
rest ifEmpty: [results add: comb copy] ifNotEmpty: [
trials := blocks at: rest first.
trials do: [:currBlk |
(0 to: 4 - currBlk width) do: [:xx | (0 to: 4 - currBlk height) do: [:yy |
currBlk displayOn: (currBox := prevBox deepCopy) at: xx@yy rule: Form paint.
currBox primCountBits = (4 * (5 - rest size)) ifTrue: [
rec copy fixTemps value: currBox value: rest allButFirst]]]]]].
rec copy fixTemps value: box value: comb]].
^results asArray sort: [:a :b | (b - a detect: [:delta | delta abs > 0] ifNone: [0]) >= 0]
"=> #(
#(1 1 1 1)
#(1 1 2 2)
#(1 1 4 4)
#(1 2 4 4)
#(1 3 3 4)
#(1 4 4 5)
#(2 2 2 2)
#(2 2 4 4)
#(3 3 3 3)
#(3 3 4 5)
#(4 4 4 4)
#(4 4 5 5))
|
Squeak Smalltalk で。組み込みの DateAndTime クラスを使用しました。
1 2 3 4 5 6 7 8 9 | | date limit buffer |
date := '0000-01-01T00:00:00' asDateAndTime.
limit := '9999-12-31T00:00:00' asDateAndTime.
buffer := (Array new: 1000) writeStream.
[ | str |
str := (date printString copyWithout: $-) first: 8.
str = str reversed ifTrue: [buffer nextPut: date].
(date := date + 1 day) <= limit] whileTrue.
buffer contents inspect; size "=> 366 "
|
Squeak Smalltalk で。
Smalltalk ではメソッドもオブジェクトで、そのソースはメソッドオブジェクト(CompiledMethod のインスタンス)の属性であるかのような扱いになっています。したがって、各メソッドに問い合わせ(getSource)て得られたソースコードの行数(lineCount)を列挙し、その平均(average)を出せば、今回調べたい平均行数が求まります。
1 2 3 4 5 | | numsOfLines |
numsOfLines := CompiledMethod allInstances collect: [:each | each getSource lineCount].
^{#調査メソッド総数-> numsOfLines size. #平均行数 -> numsOfLines average asFloat}
"=>{#調査メソッド総数->42237 . #平均行数->8.37561853351327} "
|
書き忘れましたが、新しく定義したコレクションについて collection + 2 のような処理ができるのは当然として、Smalltalk の場合、さらに、2 + collection のように交換した場合も評価可能になります。これって、今回の拡張とは全然関係のない 2(が属するクラス SmallInteger)の #+ というメソッドをコールする…というオブジェクト指向の仕組みのことを考えるとちょっと不思議で面白い機能だと思いませんか?
拡張に対するこのような柔軟性は、有名な「ダブルディスパッチ」という仕組みにより実現されています。
1 2 3 4 | | myCollection |
myCollection := MyCollection newFrom: (1 to: 3). "=> a MyCollection(1 2 3) "
myCollection + 2. "=> a MyCollection(3 4 5) "
2 + myCollection. "=> a MyCollection(3 4 5) "
|
Squeak Smalltalkでは、Collectionクラスを継承し、#add: #do: #remove:ifAbsent: #atRandom: を再定義することで、要求されるインターフェイスを満たす新たなコレクションクラスを設けることが可能です。
Bagクラスの定義が参考になるでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | Collection subclass: #MyCollection
instanceVariableNames: 'contents'
MyCollection >> add: element
^contents add: element
MyCollection >> do: aBlock
contents do: [:each | aBlock value: each]
MyCollection >> remove: element ifAbsent: aBlock
^contents remove: element ifAbsent: [aBlock value]
MyCollection >> atRandom: aGenerator
^contents atRandom: aGenerator
MyCollection >> setContents: newContents
contents := newContents
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "
MyCollection class >> new
^self new: 1
MyCollection class >> new: numElements
^super new setContents: (OrderedCollection new: numElements); yourself
MyCollection class >> newFrom: aCollection
^self withAll: aCollection
MyCollection class >> example
| myCollection |
myCollection := MyCollection newFrom: #(4 3 2 1). "=> a MyCollection(4 3 2 1) "
myCollection collect: [:each | each * 2]. "=> a MyCollection(8 6 4 2) "
myCollection select: [:each | each even]. "=> a MyCollection(4 2) "
myCollection max. "=> 4 "
myCollection * 2. "=> a MyCollection(8 6 4 2) "
myCollection atRandom "=> 3 "
|
Squeak Smalltalk で。客を一人ずつ個別のスレッドにしてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | | mutex queue tally total barber out log |
mutex := Semaphore forMutualExclusion.
queue := ValueHolder new contents: OrderedCollection new.
tally := 0.
out := SharedQueue new.
log := [:msg | out nextPut: '[', Processor activeProcess name, '] ', msg].
barber := [
[ queue contents
ifEmpty: [
log value: '床屋、眠る'.
Processor activeProcess suspend.
log value: '床屋、目覚める']
ifNotEmpty: [
log value: '散髪開始 ', queue contents first printString.
(100 to: 400) atRandom milliSeconds asDelay wait.
log value: '散髪完了 ', queue contents first printString.
mutex critical: [queue contents removeFirst].
tally := tally + 1]
] repeat
] fork.
1 to: (total := 16) do: [:id |
200 atRandom milliSeconds asDelay wait.
[ log value: '来店 ', id printString.
mutex critical: [
queue contents size < 3
ifTrue: [
queue contents add: id.
barber isSuspended ifTrue: [barber resume]]
ifFalse: [log value: '満席で立ち去る ', id printString]
]
] fixTemps fork.
id = (total // 2) ifTrue: [1.2 seconds asDelay wait]].
2 seconds asDelay wait.
barber terminate.
out nextPut: ('※ {1}人のうち {2}人を散髪' format: {total. tally}).
World findATranscript: nil.
out size timesRepeat: [Transcript cr; show: out next]
" =>
[ 3680] 床屋、眠る
[ 2177] 来店 1
[ 3680] 床屋、目覚める
[ 3680] 散髪開始 1
[ 1094] 来店 2
[ 2635] 来店 3
[ 3680] 散髪完了 1
[ 3680] 散髪開始 2
[ 233] 来店 4
[ 1666] 来店 5
[ 1666] 満席で立ち去る 5
[ 2269] 来店 6
[ 2269] 満席で立ち去る 6
[ 3680] 散髪完了 2
[ 3680] 散髪開始 3
[ 3450] 来店 7
[ 3680] 散髪完了 3
[ 3680] 散髪開始 4
[ 1056] 来店 8
[ 3680] 散髪完了 4
[ 3680] 散髪開始 7
[ 3680] 散髪完了 7
[ 3680] 散髪開始 8
[ 3680] 散髪完了 8
[ 3680] 床屋、眠る
[ 1513] 来店 9
[ 3680] 床屋、目覚める
[ 3680] 散髪開始 9
[ 3982] 来店 10
[ 2931] 来店 11
[ 164] 来店 12
[ 164] 満席で立ち去る 12
[ 2887] 来店 13
[ 2887] 満席で立ち去る 13
[ 3032] 来店 14
[ 3032] 満席で立ち去る 14
[ 3680] 散髪完了 9
[ 3680] 散髪開始 10
[ 2127] 来店 15
[ 144] 来店 16
[ 144] 満席で立ち去る 16
[ 3680] 散髪完了 10
[ 3680] 散髪開始 11
[ 3680] 散髪完了 11
[ 3680] 散髪開始 15
[ 3680] 散髪完了 15
[ 3680] 床屋、眠る
※ 16人のうち 10人を散髪 "
|
Squeak Smalltalk で。
1 2 3 4 5 6 7 8 9 10 | | utf16to8 |
utf16to8 := [:inStr |
| array str utf8 |
array :=inStr subStrings collect: [:each | Number readFrom: each base: 16].
str := array asByteArray asString convertFromEncoding: 'utf-16'.
utf8 := str convertToEncoding: 'utf-8'.
utf8 asByteArray asArray collect: [:each | (each radix: 2) forceTo: 8 paddingStartWith: $0]].
utf16to8 value: '00 41 00 42 00 43'. "=> #('01000001' '01000010' '01000011') "
utf16to8 value: '30 42 30 44 30 46'. "=> #('11100011' '10000001' '10000010' '11100011' '10000001' '10000100' '11100011' '10000001' '10000110') "
|
Squeak Smalltalk で。例題のような単純な反応式にしか使えないと思いますが。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | | molecule reactants products atoms ratios rest |
molecule := [:pairs |
Array streamContents: [:ss | pairs pairsCollect: [:a :b | b timesRepeat: [ss nextPut: a]]]].
reactants := {molecule value: #(C 2 H 2). molecule value: #(O 2)}.
products := {molecule value: #(C 1 O 2). molecule value: #(H 2 O 1)}.
ratios := Array new: reactants size + products size withAll: 0.
atoms := reactants concatenation asSet asArray.
rest := atoms collect: [:atm |
| reacCounts prodCounts |
reacCounts := reactants collect: [:reac | reac occurrencesOf: atm].
prodCounts := products collect: [:prod | prod occurrencesOf: atm].
((reacCounts occurrencesOf: 0) = (reacCounts size - 1)
and: [(prodCounts occurrencesOf: 0) = (prodCounts size - 1)])
ifTrue: [
| lcm rats |
lcm := (reacCounts detect: [:c | c > 0]) lcm: (prodCounts detect: [:c | c > 0]).
rats := lcm * (reacCounts, prodCounts collect: [:c |
c isZero ifTrue: [0] ifFalse: [1/c]]).
ratios with: rats do: [:a :b |
(b > 0 and: [a > 0]) ifTrue: [
ratios := ratios * ((a lcm: b) / a). rats := rats * ((a lcm: b) / b)]].
ratios := ratios with: rats collect: [:a :b | a isZero ifTrue: [b] ifFalse: [a]].
nil]
ifFalse: [reacCounts, prodCounts]] thenSelect: [:each | each notNil].
rest do: [:rats |
| sum idx |
sum := (ratios * rats allButFirst: reactants size) sum.
idx := rats findFirst: [:rat | rat > 0].
ratios at: idx put: sum / (rats at: idx)].
ratios := ratios * (ratios inject: 1 into: [:lcm :rat |
rat isFraction ifTrue: [lcm lcm: rat denominator] ifFalse: [lcm]]).
reactants, products with: ratios collect: [:a :b | a -> b]
"=>{#(#C #C #H #H)->2 . #(#O #O)->5 . #(#C #O #O)->4 . #(#H #H #O)->2} "
|
監視プロセスを fork するタイミングはダミーの delay の前であるべきでした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | | memo sema block |
memo := OrderedCollection new.
sema := Semaphore new.
block := nil.
block := [
| process |
process := Processor activeProcess.
memo add: {process hash. #start. Time millisecondClockValue}.
[ [Processor yield. process isTerminated] whileFalse.
memo add: {process hash. #end. Time millisecondClockValue}.
500 milliSeconds asDelay wait.
memo size < 10 ifTrue: [block copy fixTemps fork] ifFalse: [sema signal]
] fork.
100 milliSeconds asDelay wait
].
block copy fixTemps fork.
sema wait.
^memo asArray
=> #(
#(1557 #start 170533506)
#(1557 #end 170533606)
#(4003 #start 170534107)
#(4003 #end 170534207)
#(1921 #start 170534708)
#(1921 #end 170534808)
#(3790 #start 170535309)
#(3790 #end 170535409)
#(2020 #start 170535910)
#(2020 #end 170536010))
|
Squeak Smalltalk で。
監視プロセスを fork し、そのプロセスに自分の状態を監視させ、停止が確認できた 500ms 後に自分と同じ処理(監視プロセスの fork を含む)を再起動させるコードを書きました。動きが確認できるよう、memo にプロセスの id、状態、ミリ秒クロックを記録し、5 サイクル繰り返した後に memo 内容を出力してみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | | memo sema block |
memo := OrderedCollection new.
sema := Semaphore new.
block := nil.
block := [
| process |
process := Processor activeProcess.
memo add: {process hash. #start. Time millisecondClockValue}.
100 milliSeconds asDelay wait.
[ [Processor yield. process isTerminated] whileFalse.
memo add: {process hash. #end. Time millisecondClockValue}.
500 milliSeconds asDelay wait.
memo size < 10 ifTrue: [block copy fixTemps fork] ifFalse: [sema signal]
] fork
].
block copy fixTemps fork.
sema wait.
^memo asArray
=> #(
#(2387 #start 168089292)
#(2387 #end 168089395)
#(286 #start 168089897)
#(286 #end 168090005)
#(315 #start 168090505)
#(315 #end 168090606)
#(2605 #start 168091107)
#(2605 #end 168091208)
#(3727 #start 168091709)
#(3727 #end 168091809))
|
Squeak Smalltalk で。
1 2 3 4 5 6 7 8 9 10 11 12 | 3 timesRepeat: [
| rand |
rand := Random seed: 123.
Transcript cr.
5 timesRepeat: [Transcript space; show: rand next]
]
"=>
0.00096264341890935 0.1791479416094478 0.939454629989087 0.4139662265842623 0.530370201696814
0.00096264341890935 0.1791479416094478 0.939454629989087 0.4139662265842623 0.530370201696814
0.00096264341890935 0.1791479416094478 0.939454629989087 0.4139662265842623 0.530370201696814
"
|
Squeak Smalltalk で。
1 2 3 4 5 6 7 | | url user passwd args status |
url := 'http://twitter.com/statuses/update.xml'.
status := 'http://ja.doukaku.org/278/ 投稿用'.
args := {#status->{status}} as: Dictionary.
user := 'sumim'.
passwd := 'password'.
HTTPSocket httpPost: url args: args user: user passwd: passwd
|
Squeak Smalltalk で。1000 語程度にも対応できるアルゴリズムにも挑戦したいところですが、とりあえずは愚直に。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | | url allWords intermediates dict results words |
url := 'http://www.ais.riec.tohoku.ac.jp/lab/wordlist/fam55_40.txt' asUrl.
allWords := (url retrieveContents contents convertFromEncoding: #sjis) subStrings.
results := (Array new: 10 withAll: #()) asSortedCollection: [:a :b | a size > b size].
intermediates := (words := allWords shuffled first: 100) collect: [:each | OrderedCollection with: each].
dict := words groupBy: [:each | each first] having: [:group | true].
[intermediates notEmpty] whileTrue: [
| nextGen |
nextGen := OrderedCollection new.
(intermediates groupBy: [:each | each last last] having: [:group | true]) associationsDo: [:assoc |
| nexts |
nexts := dict at: assoc key ifAbsent: [#()].
assoc value do: [:each |
(nexts difference: each) ifEmpty: [results add: each; removeLast] ifNotEmptyDo: [:cands |
cands do: [:next | nextGen add: (each copyWith: next)]]]].
(intermediates := nextGen) size printString, ' ' displayAt: 0 asPoint].
^results first asArray
|
Squeak Smalltalk で。
1 2 3 4 5 6 7 8 9 10 11 12 | Display fillWhite; restoreAfter: [
| pen black white |
pen := Pen new.
black := pen color: Color black; color.
white := Color white.
[Sensor leftShiftDown] whileFalse: [
(Display colorAt: pen location) caseOf: {
[black] -> [pen color: white; turn: -90].
[white] -> [pen color: black; turn: 90]} otherwise: [].
pen down; go: 0; up; go: 1.
pen instVarNamed: #direction put: pen direction \\ 360]
]
|
Squeak Smalltalk で。
1 2 3 4 5 6 7 8 | {Time now print24. String streamContents: [:ss |
(Time now print24 subStrings: ':')
do: [:each | ss nextPutAll: (
((each asInteger radix: 2) forceTo: 7 paddingStartWith: $0)
translateWith: ({$0 asciiValue + 1 -> $□. $1 asciiValue + 1 -> $■} as: Dictionary))]
separatedBy: [ss space]]}
"=> #('22:50:58' '□□■□■■□ □■■□□■□ □■■■□■□') "
|
Squeak Smalltalk で。
M = 1000 で固定して N を 100~10000 で振ってみました。2.4GHz Core 2 Duo, Vista です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | | elapsedTime |
{1}, (5 to: 50 by: 5), (60 to: 100 by: 10) do: [:nn |
Smalltalk garbageCollect.
elapsedTime := [
| numNodes numMsgs firstMailbox neighborMailbox |
numNodes := nn * 100.
numMsgs := 1000.
firstMailbox := neighborMailbox := OrderedCollection new.
(1 to: numNodes) do: [:idx |
| myMailbox semaphore |
myMailbox := neighborMailbox.
neighborMailbox := (idx = numNodes) not
ifTrue: [OrderedCollection new]
ifFalse: [firstMailbox].
semaphore := Semaphore new.
[ | mutex numUnsent |
mutex := Semaphore forMutualExclusion.
numUnsent := numMsgs.
[numUnsent > 0] whileTrue: [
mutex critical: [
myMailbox ifNotEmpty: [
"Transcript cr; show: ('Pid = {1}, M = {2}'
format: {Processor activeProcess name. numUnsent})."
numUnsent := numUnsent - 1.
myMailbox removeFirst.
neighborMailbox add: #message]].
Processor yield].
(idx = numNodes) ifTrue: [semaphore signal]] fixTemps fork].
firstMailbox add: #message.
semaphore wait] timeToRun.
World findATranscript: nil.
Transcript cr; show: ('N = {1}, M = {2}; elapsed time = {3} milliseconds'
format: {numNodes. numMsgs. elapsedTime})]
"=>
N = 100, M = 1000; elapsed time = 276 milliseconds
N = 500, M = 1000; elapsed time = 1661 milliseconds
N = 1000, M = 1000; elapsed time = 3317 milliseconds
N = 1500, M = 1000; elapsed time = 5495 milliseconds
N = 2000, M = 1000; elapsed time = 7394 milliseconds
N = 2500, M = 1000; elapsed time = 9482 milliseconds
N = 3000, M = 1000; elapsed time = 11590 milliseconds
N = 3500, M = 1000; elapsed time = 13526 milliseconds
N = 4000, M = 1000; elapsed time = 15473 milliseconds
N = 4500, M = 1000; elapsed time = 19731 milliseconds
N = 5000, M = 1000; elapsed time = 19566 milliseconds
N = 6000, M = 1000; elapsed time = 23861 milliseconds
N = 7000, M = 1000; elapsed time = 28079 milliseconds
N = 8000, M = 1000; elapsed time = 31738 milliseconds
N = 9000, M = 1000; elapsed time = 36308 milliseconds
N = 10000, M = 1000; elapsed time = 40090 milliseconds "
|
Squeak Smalltalk で。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | "設定の作成(真偽値の場合)"
Preferences
addBooleanPreference: #myBoolPref
categories: #(unclassified)
default: false
balloonHelp: 'This is a sample boolean property.'
"設定値の変更(真偽値の場合)"
Preferences enable: #myBoolPref.
Preferences disable: #myBoolPref.
"現在の全設定の状態をファイルへ保存"
Preferences storePreferencesToDisk
"ファイルから全設定の状態を読み込み"
Preferences restorePreferencesFromDisk
|
Squeak Smalltalk で。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | | clsCount result |
clsCount := 0.
result := Dictionary new.
SystemNavigation default allBehaviorsDo: [:class |
clsCount := clsCount + 1.
result at: class put: class selectors size].
^{#全クラス数 -> clsCount. (result associations sort: [:a :b | a value > b value]) first: 10}
"=> {#全クラス数 -> 4384. {
Morph -> 1165.
Player -> 620.
PasteUpMorph -> 469.
Preferences class -> 450.
Object -> 436.
ParagraphEditor -> 284.
SyntaxMorph -> 250.
Behavior -> 243.
ScriptLoader -> 236.
String -> 233
}} "
|





sumim
#10089()
[
Smalltalk
]
Rating0/0=0.00
Squeak Smalltalk で。
まず示したスクリプトに倣って、当選番号を下一桁で分類。年賀はがきについても同様に分類して山を作り、当選番号にない下一桁の山を排除。あとは、各下一桁の山について、当選番号がないか探せばよいでしょう。山にある年賀はがきの枚数が多い場合は、下二桁について同様の作業を再帰的におこないます。
| dict | dict := { '975424' -> #1等. '259668' -> #2等. '446722' -> #2等. '630838' -> #2等. '0977' -> #3等. '00' -> #4等. '52' -> #4等. '27520' -> #C組限定 } as: Dictionary. (dict associations groupBy: [:assoc | assoc key last] having: [:g | true]) associations collect: [:assoc | assoc key -> assoc value asArray] "=> { $2->{'52'->#4等. '446722'->#2等} $4->{'975424'->#1等} $7->{'0977'->#3等} $8->{'259668'->#2等. '630838'->#2等} $0->{'27520'->#C組限定. '00'->#4等} } "Rating0/0=0.00-0+
[ reply ]