Skip to content

Instantly share code, notes, and snippets.

@zakuroishikuro
Last active November 19, 2022 15:44
Show Gist options
  • Save zakuroishikuro/55b9d17a9e58abfa9bc3fa0477c281ad to your computer and use it in GitHub Desktop.
Save zakuroishikuro/55b9d17a9e58abfa9bc3fa0477c281ad to your computer and use it in GitHub Desktop.
declare global {interface Object { log<T>(this: T, msg?): T }} // prettier-ignore
export function main(input: string): number | string {
const [A, B] = input.split(/\s/).map(Number);
return input;
}
// === ここから読む必要なし ===
const DEBUG = process.env.NODE_ENV === "test";
Object.assign(Object.prototype,{log<T>(this:T,msg="log"){if(DEBUG)console.log(`[${msg}] ${this}`);return this}}) // prettier-ignore
if (!DEBUG) {
if (process.send) console.log(main(require("fs").readFileSync(0, "utf8").trim()));
else require("child_process").fork(__filename, { execArgv: ["--stack-size=99900"] });
}
{
"configurations": [
{
"name": "Launch TypeScript Using ts-node",
"type": "node",
"request": "launch",
"env": { "NODE_ENV": "test" },
"skipFiles": ["<node_internals>/**", "node_modules/**"],
"runtimeArgs": ["--stack-size=99900", "--nolazy", "-r", "ts-node/register"],
"program": "${file}"
}
]
}
@zakuroishikuro
Copy link
Author

zakuroishikuro commented Nov 13, 2022

自分用ツールからテンプレだけ抜き出したもの。罠が多くて説明しきれないしこのまま使うのはおすすめできない。
https://github.com/zakuroishikuro/atcoderlet/blob/main/_src/_template.ts

テンプレは最小限にしたいからこれ以外の提携処理はVSCodeのスニペットに入れたりスクリプトで置換したり色々。

DEBUG

ローカルではjestかvitestでmain関数をテストする想定 (process.env.NODE_ENVが"test"になる) だった
今は .vscode/launch.json でenvにNODE_ENVを設定してVSCode + ts-nodeでF5してデバッグしてる
ここ参考にほぼコピペ https://www.walbrix.co.jp/article/debug-typescript-with-ts-node.html

このテンプレのあとに自分用ブックマークレットで開いてるページのテストケースを直接書き足してる。
答えが複数ある場合もあり、例題の出力と完全一致させればいいわけじゃないこともあるから柔軟性持たせたかった。

AtCoder上でのみ標準入力から受け取ってmainを実行
__filename.endsWith(".js") とか __dirname.includes("imojudge") とか require.main === module でもいいかもしれない

最初はjest・vitestでテストしてたけど再帰上限突破やVisualizerが絡むとifで条件分けるのめんどくさくなってきたのと、
VSCodeでブレークポイント置いてデバッグするとき遅かったり小回り利かないのでやめた。
使い捨てのコードにそんな大層なものいらないかもしれない。

再帰上限突破

child_process.forkでスクリプト自身を再帰的に実行しなおしてスタックサイズを設定してる。

ts-nodeでそのまま実行した場合、このテンプレだとTypeScriptのままNode.jsにforkされるのでエラーになる。
なのでローカルではforkされないようにして、ts-nodeなりjestなりで実行するときにstack-sizeを設定しておく。
てかもっと使いやすいように書き直したほうがいいかもしれない。自分はこれでいいけど。

あとこのテンプレ以外にWSL2の.bashrcとかにulimit -s 100000を仕込んでおく必要あり。
WSL2のUbuntuではこれ以上にするとエラーになるし十分。

AtCoder上ではそれ以上に設定してあるっぽく、stack-sizeをいくつにしても実行してくれそう。
公式ルールでも上限上げてくれようとしてたっぽいんだけど --stack-size= の位置が間違ってて効いてない。
https://atcoder.jp/contests/abc118/rules?lang=ja#:~:text=cat%20./Main.txt-,TypeScript,-(3.8)

コードテストで console.log(process.argv) してみたところ 1048576 (2^20)に設定してあるっぽかった。太っ腹
https://twitter.com/zakuro0o0o/status/1588032402743382017

VSCode Debug Visualiser

https://marketplace.visualstudio.com/items?itemName=hediet.debug-visualizer

デバッグ中に変数をグラフとして可視化したりできる → こんな感じ
他の言語でもjsonで間接的に使えるっぽいけどJavaScript/TypeScriptだとデバッグ中の変数を直接扱える
説明難しいし使いこなせてないけど設定ファイルとかはここに全部入ってる → https://github.com/zakuroishikuro/atcoderlet/

Object#log()を生やす

1行目と10行目
どのオブジェクトからもメソッドチェーンでオブジェクトの状態を標準出力に吐けるようになる
終わったら.log()を全置換で消去すればいいし、消し忘れてもAtCoder側では出力されないようになってるから安心

const array = [1,2,3];
array.log().slice(1).log().slice(1).log();

// 1,2,3
// 2,3
// 3

mainの戻り値: number | string

bigint使うときnumber感覚でreturnしちゃって10nみたいになるからtoString忘れないようにするため
まぁconsole.log側でtoStringしとけばいいんだけど何となく

Math.MAX_SAFE_INTEGERが10^14までだから、制約でそれ以上の数値があったり、計算過程で超えそうな場合は迷わずbigint使うこと

なんでTypeScript?

なぜC++やPython使わずTypeScript使ってるかは自分でもよく分からない。
C++とPython読めないと競プロの解説読めないので、TypeScriptに固執する意味はない。

JavaScriptでないのは、TypeScript側だけC++のSTLを移植したtstlってライブラリが使えるため。それだけ。
(実はJavaScript側でも/usr/lib/node_modules/tstlを直接requireすれば使える → こんな感じ

メンテナンスしていくものを作るわけじゃないので、これJavaScriptだったらもっとシンプルに書けるのにって思うこともあるけど型に助けられてることも多い。
JavaScriptみたく旧版にトランスパイルできないので||=等の複合代入演算子が一部使えないのは辛いところ。
TypeScriptはバージョン3.8だけど、tscのtarget=ESNextでトランスパイルされてv12で実行されてるので、nullish関連も使えない。

@zakuroishikuro
Copy link
Author

もうすでにけっこう変わってます。まとめなおす気は・・・・・

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment