Module nekolib_notes::debug

source ·
Expand description

デバッグ用ツールたち。

Custom Judge

入出力フォーマットは正しいことを仮定。

use std::fs::File;
use std::io::Read;

use proconio::{input, source::auto::AutoSource};

// specify judge command instead of default diff judge. The given command
// (e.g. `./judge`) will be called as
// ```
// $ ./judge input.txt actual-output.txt expected-output.txt
// ```
// and should return the result with the exit code of its `main` function.

fn main() {
    let args: Vec<_> = std::env::args().collect();
    let input = read(&args[1]);
    let actual = read(&args[2]);
    let expected = read(&args[3]);

    let mut input = AutoSource::from(input.as_ref());
    let mut actual = AutoSource::from(actual.as_ref());
    let mut expected = AutoSource::from(expected.as_ref());

    input! {
        from &mut input,
    }
    input! {
        from &mut actual,
    }
    input! {
        from &mut expected,
    }

    assert!(true);
}

fn read(path: &str) -> String {
    let mut res = "".to_owned();
    File::open(path).unwrap().read_to_string(&mut res).unwrap();
    res
}

Generator

rand = "0.8.5"
rand_chacha = "0.3.1"
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;

use nekolib::rand_gen;
use nekolib::utils::SpaceSep;
use nekolib::utils::rand_gen_macro::*;

fn main() {
    rand_gen! {
        rng: ChaCha20Rng;
    
        n in 1_usize..=10;
        a in [1_i64..=100; n];
    }
    
    println!("{n}");
    println!("{}", SpaceSep(&a));
}

Reactive

https://rsk0315.hatenablog.com/entry/2022/09/19/200454

% sniff_reactive ./solution -- ./judge testcase.in 

Reactive Runner

import asyncio
import os
import sys

[CONTESTANT, JUDGE] = range(2)
COLUMNS = os.get_terminal_size().columns

CONTMARK = "\x1b[38;5;245m↵\x1b[m"
ELLIMARK = "\x1b[38;5;245m…\x1b[m"

CROSS_TOP = "┌┬┐"
CROSS_INNER = "├┼┤"
CROSS_BOTTOM = "└┴┘"


def output(left, right, *, preleft="", preright="", cross=CROSS_INNER):
    wl = COLUMNS // 2 - 4
    wr = (COLUMNS - 1) // 2 - 4

    if not left and not right:
        print(f' {cross[0]}─{"─" * wl}─{cross[1]}─{"─" * wr}─{cross[2]}')
        return

    if left and right:
        preleft = preright = "\x1b[1;37m"

    postleft = "\x1b[m" if preleft else ""
    postright = "\x1b[m" if preright else ""

    # print(f" |{preleft} {left:{wl}} {postleft}|{preright} {right:{wr}} {postright}|")

    if wl == 0 or wr == 0 or (len(left) <= wl and len(right) <= wr):
        print(
            f" │{preleft} {left:{wl}} {postleft}│{preright} {right:{wr}} {postright}│"
        )
        return

    offl = 0
    offr = 0
    chunkl = left[offl : offl + wl]
    chunkr = right[offr : offr + wr]
    elll = " "
    ellr = " "
    while chunkl or chunkr:
        contl = CONTMARK if left[offl + wl : offl + wl + 1] else " "
        contr = CONTMARK if right[offr + wr : offr + wr + 1] else " "
        print(
            f" │{preleft}{elll}{chunkl:{wl}}{contl}{postleft}│{preright}{ellr}{chunkr:{wr}}{contr}{postright}│"
        )
        offl += wl
        offr += wr
        chunkl = left[offl : offl + wl]
        chunkr = right[offr : offr + wr]
        elll = ELLIMARK if chunkl else " "
        ellr = ELLIMARK if chunkr else " "


async def listen(read, write, who, proc):
    while proc.returncode is None:
        content = await asyncio.to_thread(read.readline)
        if content:
            contents = ["", ""]
            contents[who] = content.rstrip("\n")
            output(*contents)
            print(content, end="", flush=True, file=write)
        else:
            # 待ち続けるのを防ぐ
            write.close()
            break


async def sniff(c_read, j_read, c_write, j_write, c_proc, j_proc):
    with open(c_read, "w") as w_c_read:
        with open(j_read, "w") as w_j_read:
            with open(c_write, "r") as r_c_write:
                with open(j_write, "r") as r_j_write:
                    try:
                        await asyncio.gather(
                            listen(r_c_write, w_j_read, CONTESTANT, c_proc),
                            listen(r_j_write, w_c_read, JUDGE, j_proc),
                        )
                    except Exception:
                        pass


async def main():
    paths = ["cr.pipe", "jr.pipe", "cw.pipe", "jw.pipe"]
    [c_read, j_read, c_write, j_write] = paths
    for path in paths:
        if os.path.exists(path):
            os.remove(path)
        os.mkfifo(path)

    sep = sys.argv.index("--")
    contestant_command = " ".join(sys.argv[1:sep]) + f" < {c_read} > {c_write}"
    judge_command = " ".join(sys.argv[sep + 1 :]) + f" < {j_read} > {j_write}"

    output("", "", cross=CROSS_TOP)
    output("contestant", "judge")
    output("", "")

    devnull = asyncio.subprocess.DEVNULL
    c_proc = await asyncio.create_subprocess_shell(
        contestant_command, shell=True, stderr=devnull
    )
    j_proc = await asyncio.create_subprocess_shell(
        judge_command, shell=True, stderr=devnull
    )

    await asyncio.gather(
        sniff(c_read, j_read, c_write, j_write, c_proc, j_proc),
        c_proc.communicate(),
        j_proc.communicate(),
    )

    status = "AC"
    if c_proc.returncode != 0:
        status = "WA" if j_proc.returncode != 0 else "RE"
    elif j_proc.returncode != 0:
        status = "WA"

    preright = "\x1b[1;92m" if status == "AC" else "\x1b[1;91m"
    output("", status, preright=preright)
    output("", "", cross=CROSS_BOTTOM)

    for path in paths:
        os.remove(path)


if __name__ == "__main__":
    asyncio.run(main())

Reactive Judge

use std::env;
use std::fs::File;
use std::io::{stdin, stdout, BufReader, Write};

use proconio::{
    input,
    marker::Usize1,
    source::{auto::AutoSource, line::LineSource},
};

macro_rules! println {
    ( $($t:tt)* ) => {
        std::println!($($t)*);
        stdout().flush().unwrap();
    }
}

fn main() {
    // --- テストケース用ファイルの読み込み ---

    let infile_source = {
        let name = env::args().nth(1).unwrap();
        let file = File::open(&name).unwrap();
        AutoSource::new(BufReader::new(file))
    };

    input! {
        from infile_source,
    }

    // --- ジャッジ側の前処理 ---

    let expected = {
    };

    // --- 提出プログラムとのやり取り ---

    let stdin = stdin();
    let mut source = LineSource::new(BufReader::new(stdin.lock()));

    println!("{}", n);

    let ql = 20;
    for i in 0..=ql {
        input! {
            from &mut source,
            ty: char,
        }

        assert!(['!', '?'].contains(&ty));

        if ty == '!' {
            input! {
                from &mut source,
            }
            assert_eq!((), expected);
            return;
        }

        if ty == '?' {
            assert!(i < ql);
            input! {
                from &mut source,
            }

            let res = {
            };

            println!("{}", res);
        }
    }
}