はじめに
こちらのpaiza×Qiita記事投稿キャンペーンのCランク問題を、コードゴルフの要領で最小文字数で解答することを目指しました。
言語はJavaScriptです。
他のランクはこちら
多分これが一番短いと思います
3Dプリンタ
x=0;a=[];require('readline').createInterface({input:process.stdin}).on('line',l=>{if(x){if(l=="--"&&!--z)a.map(c=>console.log(c.join``));for(i=0;i<y;i++)if(l[i]=="#")a[z-1][i]="#"}else{[x,y,z]=l.split` `;for(i=0;i<z;)a[i++]=Array(+y).fill`.`}})
244文字
神経衰弱
N=n=0;a=[0];process.stdin.some(l=>{(0+l).split`
`.map(m=>{if(!N){[H,W,N]=m.split` `;b=Array(+N).fill(0)}else if(H-->-1||!m)a.push((" "+m).split` `);else{[e,f,g,h]=m.split` `;if(a[e][f]-a[g][h])n=N-++n?n:0;else b[n]+=2}});b.map(f=>console.log(f))})
247文字
みんなでしりとり
N=o=w=0;k={};process.stdin.some(l=>{(0+l).split`
`.map(m=>{if(N){if(K-->0)k[m]=!m.endsWith`z`;else{if(m&&(w&&!w.endsWith(m[0])||!k[m]))w=N--*n.splice(o--+1,1)*0;else k[w=m]=0;o=N-++o?o:0}}else{[N,K]=m.split` `;n=[...Array(+N+1).keys()]}});n.map(p=>console.log(p||+N))})
269文字
長テーブルのうなぎ屋
n=0;process.stdin.some(l=>{(0+l).split`
`.map(o=>{if(n){[a,b]=o.split` `;A=c=a;for(d=b-1;a--;d=n-d-1?d+1:0)c&&=!N[d];for(d=b-1;c&&A--;d=n-d-1?d+1:0)N[d]=1}else N=Array(n=+o.split` `[0])});console.log(N.filter(e=>e).length)})
224文字
名刺バインダー管理
process.stdin.some(l=>{[n,m]=(0+l).split` `;console.log(m-(m%=n*=2)+n-(m||2*n)+1)})
83文字
解説
3Dプリンタ
x=0;
a=[];
require('readline').createInterface({input:process.stdin})
.on('line',l=>{
if(x){
if(l=="--"&&!--z)a.map(c=>console.log(c.join``));
for(i=0;i<y;i++)
if(l[i]=="#")a[z-1][i]="#"
}else{
[x,y,z]=l.split` `;
for(i=0;i<z;)a[i++]=Array(+y).fill`.`
}
})
aは出力の配列です。
以下の事をしています。
- xが0の時、x,y,zに値を代入する。また、出力の配列を全て
.
で埋める - 現在の行が
--
の時、--z
を行う。zが0になれば結果を出力 - そうでなければ、現在の行に
#
がある時、a[z-1]の対応する文字を#
にする
Dランクまでで使っていた魔改造標準入力ではなくデフォルトの標準入力から文字をちょっと消したものを使っています。
入力される値がデカすぎるので、こっちでないとエラーで落ちます。
神経衰弱
N=n=0;
a=[0];
process.stdin.some(l=>{(0+l).split`
`.map(m=>{
if(!N){
[H,W,N]=m.split` `;
b=Array(+N).fill(0)
}else if(H-->-1||!m)a.push((" "+m).split` `);
else{
[e,f,g,h]=m.split` `;
if(a[e][f]-a[g][h])n=N-++n?n:0;else b[n]+=2
}
});
b.map(f=>console.log(f))})
nは現在のプレイヤー、aがカードの配列、bがプレイヤーのスコアです。
以下の事をしています。
- Nが0の時、H,W,Nに値を代入する。また、bを初期化する
- Hが-1以上の時かmが空白(仕様上、最後が空白になる)時、aにカードの値を代入する。次のelseでの参照で文字を削減するため、最初をダミーの値にして長さを1長くする。なお、Lが入力されている行もここを通る
- a[e][f]-a[g][h]で引かれたカードを判断する。同じ(0)の時は現在のプレイヤーのスコアを2加算する。異なる時は++nで次のプレイヤーに移る。ただし、N-++nが0の時は最初のプレイヤーに戻る
- 最後に出力
みんなでしりとり
N=o=w=0;
k={};
process.stdin.some(l=>{(0+l).split`
`.map(m=>{
if(N){
if(K-->0)k[m]=!m.endsWith`z`;
else{
if(m&&(w&&!w.endsWith(m[0])||!k[m]))w=N--*n.splice(o--+1,1)*0;
else k[w=m]=0;o=N-++o?o:0
}
}else{
[N,K]=m.split` `;
n=[...Array(+N+1).keys()]
}
});
n.map(p=>console.log(p||+N))})
oは現在しりとりしている人、wは1個前の言葉、kは有効な単語リスト(キーが存在して値がtrueなら有効)、nはプレイヤーリストです。
- Nが0の時、NとKとプレイヤー一覧を作る
- Kが0より大きい時、有効な単語リストを作る。ただし、末尾がzの単語はリストに追加しない
- 前の単語が存在して前の単語の末尾と現在の単語の先頭が異なる、または現在の単語が有効な単語リストに無い時、N--でプレイヤー総数を減らし、n.splice(o--,1)で現在のプレイヤーを除外し、wに0を代入して前の単語を消す
- そうでなければw=mで前の単語として現在の単語を設定する
- ++oでプレイヤーを次の人にする
- k[k.indexOf(w=m)]=""で単語リストにある現在の単語を消す
- 最後に配列の各値を出力。ただし、0の時はNを出力
長テーブルのうなぎ屋
n=0;
process.stdin.some(l=>{(0+l).split`
`.map(o=>{
if(n){
[a,b]=o.split` `;
A=c=a;
for(d=b-1;a--;d=n-d-1?d+1:0)c&&=!N[d];
for(d=b-1;c&&A--;d=n-d-1?d+1:0)N[d]=1
}else N=Array(n=+o.split` `[0])});
console.log(N.filter(e=>e).length)})
Aはaのコピー、cは座らせるフラグ、Nはその席に誰かが座っていれば1になります。
- nが0の時、nと席一覧を作る
- aとbに値を代入し、Aとcにaを代入する
- 座る予定の席を調査し、cをcと!N[d]の論理積にする。cはcがfalsyか!N[d]がfalsy(誰かが座っている)ならfalsyになる
- cがfalsyでないとき、席に人を座らせる
- 最後にNからundefinedを除いた配列の長さを座った人数として出力
名刺バインダー管理
process.stdin.some(l=>{
[n,m]=(0+l).split` `;
console.log(m-(m%=n*=2)+n-(m||2*n)+1)
})
- nとmに値を代入
- m-(m%=n*=2)をする
- まず、nにnの2倍を代入している
- 次に、mにmと2倍されたnの余りを代入している
- 最終的にm-(m%=n*=2)は
(元々のm)-(mと2倍されたnの余り)
になり、これは現在の名刺ポケットの最小の数-1
である
- 2倍されたnを加算する
- mと2倍されたnの余りが0では無い時はこの値を、0の時は2倍されたnの2倍を引く
- 最後に1を加えたものを出力する
おわりに
ここまで来ると普通に解くのも少し難しくなって来ました。
とりあえず300文字未満で解答できたので満足ですが、上3つはまだまだ改善の余地がありそうです。
一方、名刺バインダー管理は唯一100文字未満に出来たのでほぼ最小と言えるんじゃないかと思います。