MN-Core Challenge参加しました!
はじめに
2024/8/28~9/24の約1か月間開催された、PFN社のMN-Core Challengeに参加しましたので、主にその感想についてです。
※自分のコードはあんまり整備されていないのと、特に独自最短獲ったものはないので、あんまり載せません。
結果
最終的な記録は、1536点で5位でした。最終日近くでは4位以下がかなり接戦になっていて、6~10位圏に下がる公算も普通にあったので、5位に残れたのは素直に嬉しいです。
…まあ、それでも1~3位の方は開催当初から異次元のスコアの伸びを見せていて、全然追いつける感じがしませんでした。むしろ「あ、××行いけるんだ…。じゃあ、こういう実装かな」とお手本にしていた感もあります。
※コードゴルフの経験のある人には似た感覚あると思うんですけど、「××行でいける」という情報そのものが実装のヒントになって、自分の記録を押し上げる、まさにそんな感覚でした。
なお、FizzBuzz実装者がほとんどいないことを見越して、あわよくばで112行版を提出したのですが、そこは3位のtailsさんがしっかり98行版を出していて完敗しました。…それ以上に、社内記録の53行にダブルスコアで負けていると振り返り会で知った方がショックでしたが。とは言え、ほとんどの人が ( 総合成績にも結び付かないし難しそうということで ) 入り口で諦めていそうなところ、自分の実装アイデアを出すのは無駄ではないだろうと思って、143行の初提出が通った時点で振り返り会での解説発表を名乗り出ていました。使用したスライドはこちらで公開していただいてます。
コード供養
劇的な短縮にはつながらなかったものの、個人的に面白いかなと思ったものだけ載せてみます。
ほのぼのInversion系ウソ解法
こちらは実テキスト要らんでしょう、ということでスナップショットだけ。
最終2問のInversion Small, Inversionは解のバリエーションが少ないので、PEが自分の担当する範囲を XXid で判断すれば、そこそこの行数の「予め計算された解の数値を出すだけ」のコードが通ってしまいます。
いや、もちろん真面目に問題を解くという観点からは望ましくないコードですが、しかし「設定されたルールの中で最善を尽くす」という観点からは、全く手を付けないよりも何かしらポイントupを目指して足掻くというのは、あっていいんじゃないかなあ…と。
ただ、これだと上位を目指すには全く不足なので、後日ちゃんとしたコードに差し替えていますけどね。この2つを提出したのは「定数出すだけコードでも本当に通るんだっけ」という興味本位と、Tレジスタ間接参照を利用したLM0の配列的な使い方の実践を試したかったところが大きいです。
BF化命令での数値操作
FAM 8 短縮のポイントは、MAU による hvfma での2長語×4 ( 単精度16要素 ) の加算と、ALU による指数部分の調整による乗算相当処理の連携だったと後で教えていただいたわけですが、そこに辿り着かなかった私は MAU は fvfma による
最終的にALUでも、
※一部の小さい x では、fftoi時にマスクによる上位半語書き込みの抑止で or 64.0 の部分をサボれるのですが、該当する要素が少なすぎて、その線も無理でした。
が、このfftoiを使ったコードは実は提出していなくて、その前にBF化命令を使ったコードで17行を実装していました。それが
imm f"8.0" $t
imm ui"0x02000000" $ls128/1000; fvmul $aluf $aluf $lr130/1000
ipassa $subpeid $omr2; fvfma $t $lm0v $mauf $ln0v; l1bmd $mauf $lb0
ilnot $subpeid $omr1; fvfma $t $lm8v $lr130 $ln8v; l1bmd $lbi $ls0v $lr0v; noforward
lpassa $llm16v $llr16v; fvfma $t $llm16v $lr130 $lln16v; l1bmd $lbi $ls130/1000
ipassa $lr130 $nowrite; fvfma $t $lm32v $lr130 $ln32v
iadd $lm112v $ls128 $ls0v/$imr1; fvfma $t $lr18v4 $aluf $ln18v4
ipassa $aluf $lr0v/$imr2; fvfma $t $lm40v $lr130 $ln40v
fbfn $ls0v $ls112v; fvfma $t $lm48v $lr130 $ln48v
lpassa $llm56v $llr56v; fvfma $t $llm56v $lr130 $lln56v
fbfn $lr0v $ls112v/$imr2; fvfma $t $lm72v $ls130 $ln72v; l1bmd $lb0 $nowrite
iadd $lm120v $ls128 $ls0v/$imr1; fvfma $t $lr58v4 $lbf $ln58v4
ipassa $aluf $lr0v/$imr2; fvfma $t $lm80v $ls130 $ln80v
fbfn $ls0v $ls120v; fvfma $t $lm88v $lr130 $ln88v; l1bmd $lb0 $nowrite
fbfn $lr0v $ls120v/$imr2; fvfma $t $lm96v $lbf $ln96v
fvfma $t $lm104v $ls130 $ln104v
ipassa $lls112v $lln112v
浮動小数点数を整数的に処理する場面では、けち表現で隠れた最上位bitの存在がネックになるわけですが、その存在を浮かび上がらせるのが fftoi であったり fbfn であったりするわけです。今回の問題では、
…ただ、BF化命令は「ブロック内の数値の最大指数に合わせる」という処理であり、このブロックというのは fbfn の場合、同じサイクルで処理する 4PE での 1単語分 ( 長語のMSB側、LSB側別々 ) です。つまり、fbfn を使って
とは言え、BF化命令の把握という面では、この実装を考えたのは無駄ではなかったかなと思います。多分。
L1BM命令を駆使した次元入れ替え
Transpose MAB は、20行までしか縮められなくてかなり諦めが入っていた問題ですが…。
ただ、2回目の提出で25行を考えたときのデータ入れ替えがかなり綺麗に決まったので ( 行数的には全然とは言え )、これ、こんな感じで「実は短縮頑張らない想定解ってこれじゃない?」みたいに思ってました。
imm i"3" $nowrite
llsl $subpeid $aluf $t
nop
l1bmm4@0 $lmt0v $lb0
l1bmm4@1 $lmt0v $lb64
l1bmm4@2 $lmt0v $lb128
l1bmm4@3 $lmt0v $lb192
nop/2
l1bmd $lb0 $nowrite
dmwrite $lbf $lx0
dmread $lx0 $ls0v
nop
l1bmm4@0 $ls0v $lb0
l1bmm4@1 $ls0v $lb64
l1bmm4@2 $ls0v $lb128
l1bmm4@3 $ls0v $lb192
nop/2
l1bmd $lb0 $nowrite
dmwrite $lbf $lx0
dmread $lx0 $ln0v $ls0v
msr $mreadf $ln8v $ls16v
msl $ls0v $ln24v
msr $ls16v $ln16v
何をやってるかというと、4回のl1bmm4で各MABからL1BMにデータを集積したものをl1bmdで分配しその後行列レジスタ操作で転置する、というのを2セット行って次元を入れ替える、というものです。
L1BM命令には幾つか種類がありますが、それぞれで扱うデータのレイアウトが異なるため、別種の転送を組み合わせると次元入れ替えとして働くということです。
ここで登場している2種のL1BM命令は、次のような効果があります。
※添え字として出てくる
- l1bmm4x4set
LM[uu,dd,pp,ee] \Rightarrow L1BM[dd,ee,uu,pp] - l1bmd
L1BM[ee,uu,dd,pp] \Rightarrow LM[uu,dd,pp,ee]
そのため、この2種を組み合わせると次元入れ替えになります。ただ、L1BM操作だけではPEidの次元が動かないので、行列転置も組み合わせて1セットで次のような入れ替えを行います。
なので、これを2セット行うことで次のようにMABidの部分の次元と、MAB内の次元が完全に入れ替わります。
すなわちMAB内4PEで持ってる計16長語分が、MAB間で転置されていることになっているというわけです。なお最初のL1BM操作の時に、各PEでの値がばらけるようにTレジスタ間接参照を使います。
…ただ、綺麗は綺麗なんですが、種類の異なるL1BM操作の間は2ステップ間を空けなければいけないというマイナス要素もありますし、そもそもゴルフとして見ると処理に無駄が多すぎて全然です。ということで、供養対象として挙げました。
FizzBuzz実装
振り返り会での発表資料では実際のコードは載せてなかったので、一応こちらに最初の143行版と最後の112行版を載せます。実は、最初のコードでの処理のステージ分けは名前とか少し違ったりします。が、112行版は色々オーバーラップで処理が散り散りになっているので、比較対象としては最初の方がいいかなという判断です。
## const setup
iinc $subpeid $nowrite
imm i"56" $ls18/1000; dmwrite $aluf $lx0
imm ui"0x4b000000" $ls20/1000 $lr20/1000 $ln20/1000
imm i"4" $t; dmread $lx0 $ls2v $lr2v $ln2v
imm i"50" $ls22
iadd $ls2v $t $ls10v $lr32/0001
imm i"583" $ls24/1000
#imm i"8" $lr32/1000
imm f"15.0" $lr34/1000 $ln34/1000
imm i"49" $lr36/1000
imm f"90.0" $lr38/1000
imm i"35" $lr40/1000
imm f"45.0" $lr42/1000
imm i"75" $lr44/1000
imm ui"0x3e124924" $lr48/1000 # 1/7
imm ui"0x3c94f209" $lr50/1000 # 1/55
imm ui"0x3e000000" $lr52/1000 # 1/8
imm ui"0x3c820820" $lr54/1000 # 1/63
imm ui"0x3de38e39" $lr56/1000 # 1/9
imm ui"0x3c66c2b4" $lr58/1000 # 1/71
imm ui"0x3dcccccd" $lr60/1000 $ln60/1000 # 1/10
imm ui"0x3c4f6474" $lr62/1000 # 1/79
nop
## blkid(9)
# ( bbb & 6 ) << 6, ( bbb & 1 ) << 3
iand $l1bid $ls[12,2,0,0] $nowrite
ilsl $aluf $ls[12,6,0,0] $t
# ( PPPPPP & 0x38 << 6 ), ( PPPPPP & 7 ) << 0
iand $peid $ls[18,14,0,0] $nowrite
ilsl $aluf $ls[12,0,0,0] $nowrite
ior $t $aluf $t
# ccc << 4
ilsl $l2bid $ls8 $nowrite
ior $t $aluf $lr64v/1100
nop
# reduce
ior $aluf $lr66 $lr64/1000
nop
## select
isub $lr64 $ls[0,6,22,24] $omr1
ipassa $ls6v $ls30/$imr1 $lr30/$imr1
lpassa $llr32v $lls32/$llimr1
lpassa $llr48v $lls36/$llimr1
nop
## divmod
# convert bs1,8,1,blkid+cor to float
iadd $lr[8,0,0,64] $ls[30,16,2,32] $nowrite
iadd $aluf $ln20 $nowrite
fvadd $aluf -$ln20 $lr66v $ls66v $lm66v $t
# div blkid by bs2 ( cyc3 )
fvmul $mauf $ls38 $nowrite
# qf,bs2
ffloor $mauf $lr76; fvfma $t $ls66 -$lr[0,70,0,0] $ls76/0100 $ln76/0100
nop
nop
# rf
fvfma -$lr76 $ls76 $lm72 $ls78/1000 $lr78/1000
# div rf by bs1
fvmul $mauf $ls36 $nowrite
# xf
ffloor $mauf $ls80/1000 $lr80/1000
# yf
fvfma $aluf -$ls66 $lr78 $ls82/1000 $lr82/1000
nop
## off
# soff, nlap
fvfma $lr[76,82,0,0] $lm68 $ls80 $nowrite
fftoi $mauf $ls[200,84,200,200]; fvfma $mauf $ln34 -$ls34 $lr86/1000
## canvas
imm i"122" $nowrite
lpassa $aluf $llm[400,420,480,484]
lpassa $aluf $lm[406,436,456,466]
spassa $aluf $m[431,432,451,452]
imm i"70" $nowrite
spassa $aluf $m[400,419,434,449]
spassa $aluf $m[464,479,499,499]
imm i"105" $nowrite
spassa $aluf $m[401,420,435,450]
spassa $aluf $m[465,480,499,499]
imm i"66" $nowrite
spassa $aluf $m[404,429,454,483]
imm i"117" $nowrite
spassa $aluf $m[405,430,455,484]
imm i"10" $nowrite
spassa $aluf $m[408,413,418,423]
spassa $aluf $m[428,433,438,443]
spassa $aluf $m[448,453,458,463]
spassa $aluf $m[468,473,478,499]
## ftos4
ipassa $s[2,4,8,14] $s[100,101,102,103]
iadd $s[0,6,10,12] $r32 $s[104,105,106,107]
imm f"10.0" $ls98/1000 $lr98/1000
iadd $ls100v $lr20 $nowrite
fvadd $aluf -$lr20 $ls100v
fvadd $mauf $lr86 $lr100v
imm i"48" $lr96/1000; fvmul $mauf $ln60 $nowrite
ffloor $mauf $lr108v
fvfma $aluf -$ls98 $lr100v $nowrite
fftoi $mauf $ls108v; fvmul $lr108v $ln60 $nowrite
ffloor $mauf $lr116v
fvfma $aluf -$ls98 $lr108v $nowrite
fftoi $mauf $ls116v; fvmul $lr116v $ln60 $nowrite
ffloor $mauf $lr124v
fftoi $aluf $ls132v; fvfma $aluf -$ls98 $lr116v $nowrite
fftoi $mauf $ls124v
iadd $r96 $s[108,109,110,111] $m[412,417,427,442]
iadd $r96 $s[112,113,114,115] $m[447,462,472,477]
iadd $r96 $s[116,117,118,119] $m[411,416,426,441]
iadd $r96 $s[120,121,122,123] $m[446,461,471,476]
iadd $r96 $s[124,125,126,127] $m[410,415,425,440]
iadd $r96 $s[128,129,130,131] $m[445,460,470,475]
iadd $r96 $s[132,133,134,135] $m[409,414,424,439]
iadd $r96 $s[136,137,138,139] $m[444,459,469,474]
## slide
isub $lr30 $ls12 $ls140/1000
ipassa $aluf $m609v $t
iadd $aluf $ls140 $nowrite
ipassa $aluf $mt614v; l1bmd $aluf $lbi
ipassa $aluf $lmt618v; l1bmd $lbi $t
iadd $aluf $ls140 $nowrite
ipassa $aluf $mt624v
ipassa $aluf $mt628v; l1bmd $aluf $lbi
ipassa $aluf $lmt632v; l1bmd $lbi $t
iadd $aluf $ls140 $nowrite
ipassa $aluf $mt639v $t
iadd $aluf $ls140 $nowrite
ipassa $aluf $mt644v
ipassa $aluf $mt648v; l1bmd $aluf $lbi
ipassa $aluf $lmt652v; l1bmd $lbi $t
iadd $aluf $ls140 $nowrite
ipassa $aluf $mt659v; l1bmd $aluf $lbi
ipassa $aluf $lmt662v; l1bmd $lbi $t
iadd $aluf $ls140 $nowrite
ipassa $aluf $mt669v $t
iadd $aluf $ls140 $nowrite
ipassa $aluf $mt674v
ipassa $aluf $lmt678v
## blk
iadd $ls84 $lr0v $t $ls160v
iadd $aluf $ls8 $ls168v
ipassa $mt600 $r161v2
ipassa $ls168v $t
isub $ls160v $lr160v $ls160v
ipassa $mt600 $r169v2
ipassa $ls160v $t
isub $ls168v $lr168v $ls168v
ipassa $mt400 $r200v2
ipassa $ls168v $t
nop
ipassa $mt400 $r201v2
## reduce
ilsl $lr[6,4,2,0] $ls6 $nowrite
ilsl $lr200v $aluf $ls208v $lr208v
nop
ior $ls[208,0,212,0] $lr[210,0,214,0] $ls208v $lr208v
nop
ior $ls[0,208,0,0] $lr[0,212,0,0] $ls208v $lr208v
## merge(8)
l1bmd $aluf $lb0
nop/2
l2bmd $lb64 $lc0
l2bmd $lb96 $lc256
nop
mvd/n512i01 $lc0 $p0@0
mvp/n4096i02 $p0@0 $d0@0
## const setup(20)
iinc $subpeid $nowrite
imm i"56" $ls18/1000; dmwrite $aluf $lx0
imm i"4" $t; dmread $lx0 $ls2v $lr2v $ln2v
imm i"50" $ls22
iadd $ls2v $t $ls10v $lr32/0001
imm i"583" $ls24/1000
#imm i"8" $lr32/1000
imm f"15.0" $lr34/1000 $ln34/1000
imm i"49" $lr36/1000
imm f"90.0" $lr38/1000
imm i"35" $lr40/1000
imm f"45.0" $lr42/1000
imm i"75" $lr44/1000
imm ui"0x3e124924" $lr48/1000 # 1/7
imm ui"0x3c94f209" $lr50/1000 # 1/55
imm ui"0x3e000000" $lr52/1000 # 1/8
imm ui"0x3c820820" $lr54/1000 # 1/63
imm ui"0x3de38e39" $lr56/1000 # 1/9
imm ui"0x3c66c2b4" $lr58/1000 # 1/71
imm ui"0x3dcccccd" $lr60/1000 $ls60/1000 # 1/10
imm ui"0x3c4f6474" $lr62/1000 # 1/79
## canvas(2)
imm i"122" $n[431,482,485,999]
imm i"10" $n[428,999,999,999]; l1bmd $aluf $lb0
## blkid(9)
# ( bbb & 6 ) << 6, ( bbb & 1 ) << 3
iand $l1bid $ls[12,2,0,0] $nowrite; l1bmd $aluf $lb256
ilsl $aluf $ls[12,6,0,0] $t; l1bmd $lbi $m[473,478,999,999]
# ( PPPPPP & 0x38 << 6 ), ( PPPPPP & 7 ) << 0
iand $peid $ls[18,14,0,0] $nowrite
ilsl $aluf $ls[12,0,0,0] $nowrite; l1bmd $lb0 $lm[402,406,420,422]
ior $t $aluf $t; l1bmd $lb0 $lm[432,436,450,452]
# ccc << 4
ilsl $l2bid $ls8 $nowrite
ior $t $aluf $lr64v/1100 $ls64v/1100; l1bmd $lb0 $lm[456,466,480,486]
imm ui"0x4b000000" $ls20/1000 $lr20/1000 $ln20/1000 # const overlapped
# reduce
ior $ls64 $lr66 $lr64/1000; l1bmd $lb256 $m[408,413,418,423]
## select(5)
isub $aluf $ls[0,6,22,24] $omr1; l1bmd $lb256 $m[433,438,443,448]
ipassa $ls6v $ls30/$imr1 $lr30/$imr1; l1bmd $lb256 $m[453,458,463,468]
lpassa $llr32v $lls32/$llimr1
lpassa $llr48v $lls36/$llimr1
ilsl $lr[6,4,2,0] $ls6 $ls216v # const overlapped
## position(14)
# convert bs1,8,1,blkid+cor to float
iadd $lr[8,0,0,64] $ls[30,16,2,32] $nowrite
iadd $aluf $ln20 $nowrite
fvadd $aluf -$ln20 $lr66v $ls66v $lm66v $t
# div blkid by bs2 ( cyc3 )
imm i"70" $n[400,434,999,999]; fvmul $mauf $ls38 $nowrite
# qf,bs2
ffloor $mauf $lr76; fvfma $t $ls66 -$lr[0,70,0,0] $ls76/0100 $ln76/0100; l1bmd $aluf $lbi
ipassa $s[2,4,8,14] $s[100,101,102,103] #ftos4 overlapped
iadd $s[0,6,10,12] $r32 $s[104,105,106,107] #ftos4 overlapped
# rf
fvfma -$lr76 $ls76 $lm72 $ls78/1000 $lr78/1000
# div rf by bs1
imm i"105" $n[401,435,999,999]; fvmul $mauf $ls36 $nowrite
# xf
ffloor $mauf $ls80/1000 $lr80/1000; l1bmd $aluf $lb256; l1bmd $lbi $m[419,449,464,479]
# yf
imm i"66" $n[404,429,454,483]; fvfma $aluf -$ls66 $lr78 $ls82/1000 $lr82/1000
imm f"10.0" $ls98/1000 $lr98/1000 # ftos4 overlapped
## off
# soff, nlap
fvfma $lr[76,82,0,0] $lm68 $ls80 $nowrite
fftoi $mauf $ls[200,84,200,200]; fvfma $mauf $ln34 -$ls34 $lr86/1000
## ftos4(15)
iadd $ls100v $lr20 $nowrite
imm i"117" $n[405,430,455,484]; fvadd $aluf -$lr20 $ls100v # ls100v: offset(f)
fvadd $mauf $lr86 $lr100v # lr100v: n
imm f"48.0" $lr96/1000; fvmul $mauf $ls60 $nowrite
ffloor $mauf $lr108v; l1bmd $lb256 $m[420,450,465,480] # lr108v: n/10
fvfma $aluf -$ls98 $lr100v $t; l1bmd $ln[400,404,428,430] $lbi # t: n%10
fvmul $lr108v $ls60 $nowrite; l1bmd $lbi $lm[400,404,428,430]
ffloor $mauf $lr116v; fvadd $lr96 $t $nowrite; l1bmd $ln[434,454,482,484] $lbi # lr116v: n/100
fftoi $mauf $ls100v $m[412,427,447,472]; fvfma $aluf -$ls98 $lr108v $t; l1bmd $lbi $nowrite # t: n/10%10
fvmul $lr116v $ls60 $ls124v; l1bmd $lbf $lbi # ls124v: n/1000
ffloor $mauf $nowrite; fvadd $lr96 $t $nowrite; l1bmd $s101v2 $lbi; l1bmd $lbi $lm[434,454,482,484]
fftoi $mauf $ls108v $m[411,426,446,471]; fvfma $aluf -$ls98 $lr116v $nowrite; l1bmd $lbi $nowrite
ipassa $lbf $m[417,442,462,477]; fvadd $lr96 $mauf $nowrite;
fftoi $mauf $ls116v $m[410,425,445,470]; fvadd $lr96 $ls124v $nowrite
fftoi $mauf $ls124v $m[409,424,444,469]
#ipassa $s109v2 $m[416,441,461,476]
#ipassa $s117v2 $m[415,440,460,475]
#ipassa $s125v2 $m[414,439,459,474]
## slide(23)
isub $lr30 $ls12 $lr140/1000
ipassa $aluf $m609v $t; l1bmd $s109v2 $lb0 # overlapped ftos4
iadd $aluf $lr140 $nowrite; l1bmd $s117v2 $lb256 # overlapped ftos4
ipassa $aluf $mt614v; l1bmd $aluf $lbi
ipassa $aluf $lmt618v; l1bmd $lbi $t
iadd $aluf $lr140 $nowrite; l1bmd $s125v2 $lb512 # overlapped ftos4
ipassa $aluf $mt624v
ipassa $aluf $mt628v; l1bmd $aluf $lbi
ipassa $aluf $lmt632v; l1bmd $lbi $t
iadd $aluf $lr140 $nowrite; l1bmd $lb0 $m[416,441,461,476] # overlapped ftos4
ipassa $aluf $mt639v $t
iadd $aluf $lr140 $nowrite; l1bmd $lb256 $m[415,440,460,475] # overlapped ftos4
ipassa $aluf $mt644v
ipassa $aluf $mt648v; l1bmd $aluf $lbi
ipassa $aluf $lmt652v; l1bmd $lbi $t
iadd $aluf $lr140 $nowrite; l1bmd $lb512 $m[414,439,459,474] # overlapped ftos
ipassa $aluf $mt659v; l1bmd $aluf $lbi
ipassa $aluf $lmt662v; l1bmd $lbi $t
iadd $aluf $lr140 $nowrite
ipassa $aluf $mt669v $t
iadd $aluf $lr140 $nowrite
ipassa $aluf $mt674v
ipassa $aluf $lmt678v
## makeblk(16)
iadd $ls84 $lr0v $t $ls160v
iadd $aluf $ls8 $ls168v
ipassa $mt600 $r161v2
ipassa $ls168v $t
isub $ls160v $lr160v $ls160v
ipassa $mt600 $r169v2
ipassa $ls160v $t
isub $ls168v $lr168v $ls168v
ilsl $mt400 $ls216v $s208v2 $r208v2
ipassa $ls168v $t
nop
ilsl $mt400 $ls216v $s209v2 $r209v2
nop
ior $ls[208,0,212,0] $lr[210,0,214,0] $ls208v $lr208v
nop
ior $ls[0,208,0,0] $lr[0,212,0,0] $ls208v $lr208v
## merge(8)
l1bmd $aluf $lb0
nop/2
l2bmd $lb64 $lc0
l2bmd $lb96 $lc256
nop
mvd/n512i01 $lc0 $p0@0
mvp/n4096i02 $p0@0 $d0@0
おわりに
この1か月、頭を悩ませつつも非常に楽しんで参加できました。振り返り会・懇親会でも色々お話できて楽しかったです。運営のPFNの方々にはとても感謝しています。同じコンセプトでの開催はそう頻繁に無いとは思っていますが、実アプリ的な問題セットへの挑戦とか、別方面で開催されてもそれはそれで色々面白そうなので、また機会があれば是非参加したいと思います。
Discussion