const stdinIter = Deno.stdin.readable[Symbol.asyncIterator](); const getStdinAsText = async (): Promise => new TextDecoder().decode( (await stdinIter.next()).value ); const matched = (await getStdinAsText()).match(/(\d+)\s(\d+)/) ?? []; const N = parseInt(matched[1]); const Q = parseInt(matched[2]); /** n=0で"A"を返す */ const toChar = (n: number):string => String.fromCharCode(65 + n); const chars = [...Array(N).keys()].map((_,i) => toChar(i)); const ask = async (a: string, b: string): Promise<-1 | 1> => { console.log(`? ${a} ${b}`); const input = await getStdinAsText(); // 改行が入ってしまうようなので、trimしておく switch (input.trim()) { case "<": return -1; case ">": return 1; dafault: throw new Error("不正な値を入れやがったな!シベリア送りだ!!"); }; throw new Error("こんなところにきたやつはシベリア送りだ!!"); }; const sort = async (list: T[], compareFn: (a: T, b: T) => Promise): Promise => { // 比較結果をcacheする const cache = new Map(); const compare = async (a: T, b: T): Promise => { const key = `${a} ${b}`; const cached = cache.get(key) ?? await compareFn(a, b); cache.set(key, cached); return cached; }; /** `target`をsort済みの`sorted`に挿入する */ const insert = async (sorted: readonly T[], target: T, offset?: number, length?: number): Promise => { offset ??= 0; length ??= sorted.length; if (length === 0) return [target]; if (length === 1) { if ((await compare(target, sorted[offset])) < 0) { return [...sorted.slice(0, offset), target, ...sorted.slice(offset)]; } else { return [...sorted.slice(0, offset + 1), target, ...sorted.slice(offset + 1)]; } } // 二分探索っぽく挿入位置を決定する if (length % 2 === 0) { // ... | before | after | ... // ↑ ↑ どちらに入るか調べる const newLength = length / 2; const after = sorted[offset + newLength]; if ((await compare(target, after)) < 0) { return await insert(sorted, target, offset, newLength); } else { return await insert(sorted, target, offset + newLength, newLength); } } // ... | before | middle | after | ... // ↑ ↑ どちらに入るか調べる const newLength = (length - 1) / 2; const middle = sorted[offset + newLength]; if ((await compare(target, middle)) < 0) { return await insert(sorted, target, offset, newLength); } else { return await insert(sorted, target, offset + newLength + 1, newLength); } }; let sorted: T[] = []; for (const target of list) { sorted = await insert(sorted, target); } return sorted; }; // test // console.log(await sort(chars, (a,b) => Promise.resolve(new Intl.Collator().compare(a,b)))) // console.log(await sort([97,4,31,34,6,53,45,5], (a,b) => Promise.resolve(a-b))) console.log(`! ${(await sort(chars, ask)).join("")}`);