ちょっと前のネタになりますが、今年2021年5月に「ZONeエナジー プログラミングコンテスト “HELLO SPACE”」というのが実施されました。
内容はいわゆる競プロ、競技プログラミングなのですが、ストーリーが面白いですね。
宇宙人が襲来し、彼らが送ってきたメッセージを解読し、それからどうしよう、という内容です。
やってることは競プロですけど、バックストーリーがあったりするとやる気が出ます。

私は2nd ROUNDから参加し、3つの課題すべてをrustで書いてみました。

今回の記事では1つ目のお題、rot13暗号解読のrust版実装例を提示したいと思います。

お題1

宇宙人の謎のメッセージを解読する。メッセージはrot13という暗号化がなされている。
rot13は各文字のASCIIコードを13ずらすという暗号化。
(参考:https://ja.wikipedia.org/wiki/ROT13)

rot13解説

例えばhという文字をrot13で変換することを考えましょう。
hのASCIIコードは104、13を足すと117、ASCIIコードが117の文字はu、
ということでh→uと変換されます。この要領で行くと、例えば”hello”という文字列は
h→u
e→r
l→y
l→y
o→b(zを超えた場合はaから再度カウントする)
ということで、”uryyb”となります。
課題はこれを解読することなので、逆変換、つまり13引く処理になります。

実装例

question1.rs

use std::io;

fn main() {
    let mut input = String::new();
    let n_alpha = 'z' as u8 - 'a' as u8 + 1;
    while let Ok(n) = io::stdin().read_line(&mut input) {
        if n == 0 { break; }
        let s = input
            .trim()
            .bytes()
            .map(|c: u8| ((c - 'a' as u8 + 13) % n_alpha + 'a' as u8) as char)
            .collect::<String>();
        println!("{}", s);
        input.clear();
    }
}

入力テキスト

question1.txt

puvxlhwva
fubxha
tbxvtralb
jnerjnerun
xvzvgnpuvgb
lhxban
xnaxrvjb
xvmhxhgnzr
xbabubfuvav
lnggrxvgn
fnffbxhqntn
lhxbab
fuvehfuvgbfvgr
chermragbjb
bartnvfuvgnv
ranwvqbevaxh
mbar
jb
whaovfuvgr
ubfuvvabqn
xbabartnvjb
xnanrgrxhereron
bgbanfuvxh
xbabubfuvjb
ngbavfhehgfhzbevqn
jnerjnerun
nenfbvtbgbjb
abmbznanv
znrzhxvan
urawvjb
xvgnvfuvgrveh

使用例

>question1.exe < question1.txt

出力結果

chikyujin
shokun
gokigenyo
warewareha
kimitachito
yukona
kankeiwo
kizukutame
konohoshini
yattekita
sassokudaga
yukono
shirushitosite
purezentowo
onegaishitai
enajidorinku
zone
wo
junbishite
hoshiinoda
kononegaiwo
kanaetekurereba
otonashiku
konohoshiwo
atonisurutsumorida
warewareha
arasoigotowo
nozomanai
maemukina
henjiwo
kitaishiteiru

ソースコードについて

まだそんなにRustに慣れているわけではないので、標準入力を読み取るのにも苦労しました。入力の書き方については例えば:

use std::io;
use std::io::prelude::*;

for line in io::stdin().lock().lines() {
    println!("{}", line.unwrap()); // ここに各行が読み込まれる
}

のように書く方が関数型っぽくって格好いいんですが、処理が遅いらしいので question1.rs のようなコードにしました。なにやらlines()は行を読むたびにメモリアロケーションが起きるそうで、それよりはあらかじめ入力バッファ(question1.rsではString型変数inputがそれに対応)を用意するのがいいんだとか。

まとめ

rustはC~Java系統をやってきた私にとっては構文が独特ですが、C/C++相当のローレベル言語でありながら関数型的に流れるように書けるので慣れてくれば書きやすくも読みやすくもなると思いました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です