LoginSignup
0
0

More than 5 years have passed since last update.

オフラインリアルタイムどう書くE27の参考問題の実装例(Rust)

Posted at

オフラインリアルタイムどう書く E27の参考問題「灯りと鏡」の実装例を、Rust で。

問題 : http://nabetani.sakura.ne.jp/hena/orde27ligmir/
実装リンク集 : https://qiita.com/Nabetani/items/0b2f459ec128c89948f4

次回のイベントは 12/8。
詳しくは
https://yhpg.doorkeeper.jp/events/82699
を御覧ください。
まだ問題も決まってないけど、 Rust での実装例を用意したいと思っている(未定) ので、Rust 好きの方も是非。

で。
実装例は以下の通り。

Rust
const W: isize = 5; // width
const H: isize = 5; // height
const PWS: isize = W + 1; // positive width with separator
const NWS: isize = -PWS; // negative width with separator

fn pos_to_xy(pos: isize) -> (isize, isize) {
    (pos % PWS, pos / PWS)
}

fn step(curpos: isize, dir: isize) -> Option<isize> {
    let (x, y) = pos_to_xy(curpos);
    let okay = match dir {
        NWS => 0 < y,
        PWS => y + 1 < H,
        -1 => 0 < x,
        1 => x + 1 < W,
        _ => panic!("unexpected direction"),
    };
    if okay {
        Some(curpos + dir)
    } else {
        None
    }
}

fn mirror0(dir: isize) -> isize {
    match dir {
        PWS | NWS => dir / PWS,
        1 | -1 => dir * PWS,
        _ => panic!("unexpected direction"),
    }
}

fn run(src: &String, passed: &mut Vec<isize>, mut curpos: isize, mut dir: isize) {
    for _i in 0..(W * H * 2) {
        passed.push(curpos);
        let nextpos_opt = step(curpos, dir);
        match nextpos_opt {
            Some(nextpos) => {
                let nextcell = src.chars().nth(nextpos as usize).unwrap() as u8 as char;
                dir = match nextcell {
                    '.' | 'Y' => dir,
                    '0' => mirror0(dir),
                    '1' => -mirror0(dir),
                    'x' => return,
                    _ => panic!("unexpected direction"),
                };
                curpos = nextpos;
            }
            _ => {
                return;
            }
        }
    }
}

fn solve(src: &String) -> String {
    let you = src.find('Y').unwrap() as isize;
    let mut passed = Vec::<isize>::new();
    run(src, &mut passed, you, -6);
    let mut places = passed
        .iter()
        .map(|pos| {
            let (x, y) = pos_to_xy(*pos);
            ((x + y * W + 'a' as isize) as u8 as char).to_string()
        }).collect::<Vec<String>>();
    places.sort_unstable();
    places.dedup();
    places.join("")
}

fn test(num: i32, src: String, expected: String) {
    let actual = solve(&src);
    let okay = actual == expected;
    println!(
        "{}, {}, src: {}, act: {}, exp: {}",
        num,
        if okay { "ok" } else { "**NG**" },
        src,
        actual,
        expected
    );
}

macro_rules! test {
    ($n:expr, $x:expr, $y:expr) => {
        test($n, $x.to_string(), $y.to_string());
    };
}

fn main() {
    test!(0, "x...x/.1.0./..0../.Y.../0..x.", "ghilnqs");
    test!(1, "..Y../...../...../...../.....", "c");
    test!(2, "..x../..Y../...../...../.....", "h");
    test!(3, "..Y.x/..1x0/11.../....0/1..1.", "c");
    // 中略
    test!(
        45,
        "1...0/.1.0./..1../..01./Y0..1",
        "abcdefghijklmnopqrstuvwxy"
    );
}

いつもどおりテストの大半は省略。

問題が簡単だったせいか、わりとすんなり書けた。

今回書き方がわからなかったのは

Rust
    let okay = match dir {
        MWS => 0 < y,
        PWS => y + 1 < H,
        -1 => 0 < x,
        1 => x + 1 < W,
        _ => panic!("unexpected direction"),
    };

の部分。本当は

Rust
    let okay = match dir {
        -(W+1) => 0 < y,
        (W+1) => y + 1 < H,
        -1 => 0 < x,
        1 => x + 1 < W,
        _ => panic!("unexpected direction"),
    };

って書きたかったんだけど、エラーだった。
=> の左辺に式は書けないのかと思って定数を書いたら通った。そういうものか。

あと、Rust 全般についての感想。

すぐにコンパイルエラーになって、そこは怖いんだけど、エラーメッセージはわりと親切だしわかりやすいと思う。

今回は、コンパイルエラーが出なくなったらいきなり動いて、いきなり全部テスト通った。びっくりした。恐れ入った。

VSCode で書いているんだけど、環境は今ひとつかな。
Go みたいに

  • まずいところは下線が付く
  • 保存時に勝手にフォーマット

というようになると幸せになると思うけど、拡張機能の探し方が悪いのかそうはなっていない。残念。

※皆様はどんな エディタ / IDE で Rust 書いてますか?

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0