五月祭2020 Live CodeGolf Contest Day2 参加記
TSG LIVE! 5(2日目)のライブコードゴルフ大会に、こたつがめさんとともに外部ゲストプレイヤーとして参加させてもらいました。
TSG LIVE! でコードゴルフ大会が行われていることは以前から知っていて、参加したいと思っていたので、参加できる機会を与えてくださったことに感謝しています。
リンク
- アーカイブ動画
- こたつがめさんによる参加記(この記事を書き終わってから存在を知ったので、この記事に載っている情報は若干古いです)
競技規則
- 競技時間は75分
- 出力の空白・改行は余計にあってもよい
- 出力が正しければエラー終了でもよい
- 出力が正しく言語内最短を更新したときのみマスをとれる
- 自分チームがとったマスと隣接するマスにのみ提出できる
- 自分チームの提出コードは見ることができる
- 相手チームの提出コードは見ることができない
- 相手チームの提出言語、ジャッジ結果、コード長、提出時刻、提出者名は見ることができる
- チームメイトとテキストでコミュニケーションをとってもよい
参加記
C
こたつがめさんが開始から3分で提出(55B)
main(a,p){for(;~scanf("%d",&a);)puts(p>a?p=a,"1":"0");}
ぱっと見で縮みそうなところがなかったので放置していた。結局これが最後まで最短として残った。
Ruby
とりあえずできたので提出した(38B)
x=100;p *$<.map{x>(a=_1.to_i)?a/x=a:0}
入力はランダムに1ケース作られるだけなので初期値を 99
にしてもバレなさそう(37B)
x=99;p *$<.map{x>(a=_1.to_i)?a/x=a:0}
p
を内側に入れて *
を消した(36B)
x=99;$<.map{p x>(a=_1.to_i)?a/x=a:0}
文字列として扱ったほうが短いよね(32B)
x=?:;$<.map{p x>_1 ? (x=_1;1):0}
まだ縮むような気もするが競技時間は75分しかないので別の言語へ。
後に相手チームのうらさんが提出したコード(31B)
s=?@
$<.map{p _1<s ?(s=_1;1):0}
それはそう。Rubyでは ?
がいろいろな意味を持つので、条件演算子の ?
の前後にスペースが必要になる場合があるが、この条件がややこしいので、分からなければ全部試すというのが有効で、きちんと試し切っていれば31Bにできていた。
Go
こたつがめさんがやっていた。Goに詳しくないので見ても分からないだろうと思い、ほとんど見ていない。
序盤にとりあえず提出し、終盤に縮めたようだ(87B)
package main
import."fmt"
func main(){p:=100;for{a:=0;Scan(&a);if p>a{p=a};Print(p/a)}}
Python3
Pythonは相手チームにも提出権があり、しかもRubyと似ているのでとりあえず提出した(54B)
x=':'
while 1:
t=input()
u=x>t
if u:x=t
print(u+0)
バージョンを確認していなかったので :=
をcheckerで試した結果、使えないらしいという結論を得ていた。
が、これは勘違いで、すぐにこたつがめさんが :=
を使って縮めていた(52B)
x=':'
while t:=input():
u=x>t
if u:x=t
print(u+0)
:=
を使って縮むところがもう1か所(50B)
x=':'
while t:=input():
if u:=x>t:x=t
print(u+0)
単項の +
でも整数に変換できるらしい(49B)
x=':'
while t:=input():
if u:=x>t:x=t
print(+u)
後に相手チームのhakatashiさんが提出したコード(48B)
j="Z"
for n in open(0):j=min(j,n);print(1-(j<n))
Python3ゴルフで入力を読み込む常套手段である open(0)
を利用しているが、実は while t:=input():
と for n in open(0):
の字数は同じ。
今までに見た中での最小値を更新してしまってから更新があったかどうかを判定しているのが短縮ポイントらしい。
Perl
相手チームはPerlの提出権がないのでGolfScriptをやろうとしていたが、できなかったのでPerlをやった。
とりあえず提出したコード(29B)
print$~gt$_?$_/($~=$_):0for<>
$~
は初期値が "STDOUT"
なので、"99\n"
よりも辞書順で大きい。結局これが最後まで最短として残った。
終了後の今見ると、ジャッジ環境の $$
(PID)の値次第だが縮む可能性がある(28B)
print$$>$_?$_/($$=$_):0for<>
GolfScript
こたつがめさんがやっていた(27B)
今までにGolfScriptを触った経験から、もっと縮むはずと思っているので詳細は省略。
相手チームが提出してこなかったので一応勝ちは勝ち。
Crystal
こちらのチームがGolfScriptに提出したのを見て相手チームが防衛のために縮めていたらしい。
元々のコード(60B)
j=99
while l=read_line.to_i
p(if j > l
j=l;1
else
0
end)
end
縮めた後のコード(42B)
j="Z"
STDIN.each_line{|n|p j>n&&(j=n)?1:0}
見るからに入力を読み込む部分が長いなぁという印象。
Crystalは一応書いたことはあるものの、入力の読み込み方を忘れたので調べてみると、gets
でできるらしい。
後置 while
や $_
(gets
で読み込んだ文字列が自動的に代入される変数)がないことに対して不便だなぁと思いながら適当に書いたら相手チームより短かった(39B)
x=":"
while s=gets
p x>s ?(x=s;1):0
end
直後にこたつがめさんが1B縮めた(38B)
x=":"
while a=gets
p x>a ?(x=a;1):0end
Whitespace
相手チームの提出権がないので急ぐ必要はないものの、残り時間も減ってきたのでやった(79B)
スペースを S
、タブを T
、改行を N
に変換したコードで解説する。
コード | 意味 | 備考 |
SS(S)[TTSSTSS]N |
push 100 |
(S) =+,[TTSSTSS] =100 |
NSS[]N |
label "" |
ラベル名は空にできる |
SNS |
dup |
|
SNS |
dup |
|
SNS |
dup |
|
TNTT |
readnum |
整数の入力を1行読み込み、配列の(top of stack)番目に代入する |
TTT |
retrieve |
配列の(top of stack)番目の値をスタックに載せる |
STS(S)[T]N |
copy 1 |
(S) =+,[T] =1 |
TSST |
- |
(読み込んだ値)-(現在の最小値) |
NTT[S]N |
jump(<0) "S" |
|
SS(S)[]N |
push 0 |
0の場合は符号だけで可 |
TNST |
writenum |
|
NSN[]N |
jump "" |
|
NSS[S]N |
label "S" |
|
TTT |
retrieve |
もとの最小値が今スタックトップにあることを利用 |
SS(S)[T]N |
push 1 |
|
TNST |
writenum |
|
NSN[]N |
jump "" |
以前は古いPCでWhitespace用のエディタを自作して使っていた(バックアップはとっていなかった)のだが、そのPCが割と最近壊れたので、メモを紙に書いた後、普通のエディタで書いた。その結果、少し間違えた(ちょうどその部分が放送で映されている)。
終了後に見返すと、自明な無駄と容易な改善方法があって、計6B縮む。
3連続dupは1回余計で、全く使われることなく残ってしまう要素があるので2連続dupでよい(76B)
分岐の仕方を、a-b<0?c:d
から b-a<0?d:c
に変えることで、copy 1
の代わりに dup
が使えるようになる(73B)
コード | 意味 | 備考 |
SS(S)[TTSSSTT]N |
push 99 |
|
NSS[]N |
label "" |
|
SNS |
dup |
|
SNS |
dup |
|
SNS |
dup |
|
TNTT |
readnum |
|
TTT |
retrieve |
|
TSST |
- |
(現在の最小値)-(読み込んだ値) |
NTT[S]N |
jump(<0) "S" |
|
TTT |
retrieve |
|
SS(S)[T]N |
push 1 |
|
TNST |
writenum |
|
NSN[]N |
jump "" |
|
NSS[S]N |
label "S" |
|
SS(S)[]N |
push 0 |
|
TNST |
writenum |
|
NSN[]N |
jump "" |
><>
Whitespaceの前に書こうか迷っていた。こたつがめさんが46B、45B。たぶんまだ縮むので詳細は省略。
相手チームの提出権がないので縮める必要もなかった。
この言語の厄介なところは、入力を1Bずつしか読み込めないことと、エラーメッセージが全て同じことで、命令が豊富な割に、書いてみると結構つらい。
Node.js
よく知らない。相手チームがやっていた。提出権はあったのでやろうとしても良かったかもしれない。
Starry
終盤でCrystalをとったことで提出権を得たが、時間が足りないのでやろうとしなかった。
分岐命令が !=0
しかないので書きづらいが、方針は立っているのでそのうちやりたい(やるとは言ってない)