2️⃣

Rustを勉強しようと思ったらgithub copilotに全部書かれた

2024/03/02に公開

最近Rustの勉強を始めました。

The Bookの7章ぐらいまで呼んだところで無性に何かを作りたくなったので、オセロを作ることにしました。

完全にオセロを再現することが目的ではなく、あくまで「それっぽく」ターミナル上で動くものを作れたらと思い、コードを書き始めました。

成果物

とりあえず必要なものをコメントでメモしようとすると、あれよあれよという間にコードが生成されていくのです...!自分でコード書きたいのに。笑

github copilotは便利だし、日頃の業務で助けてくれるけど勉強する時はあえてOFFにした方が良いかもしれないですね。

完成したコードがこちら。
自分が手を加えたのは、オセロの盤面での表示ぐらいです。笑

コード

fn main() {
    let mut board = Board::new();
    board.print();

    // ループを使って交互に石を置く
    let mut turn = Stone::Black;
    loop {
        println!("{:?}のターンです", turn);

        let mut input = String::new();
        std::io::stdin().read_line(&mut input).unwrap();
        let input: Vec<usize> = input
            .split_whitespace()
            .map(|s| s.parse().unwrap())
            .collect();
        board.put(input[0], input[1], turn);
        board.reverse(input[0], input[1], turn);
        board.print();
        turn = match turn {
            Stone::Black => Stone::White,
            Stone::White => Stone::Black,
            Stone::None => Stone::None,
        };
    }
}

// オセロの盤面を表す構造体
const BOARD_SIZE: usize = 8;

// オセロの石を表す列挙型
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum Stone {
    Black,
    White,
    None,
}

// オセロの盤面を表す構造体
struct Board {
    board: [[Stone; BOARD_SIZE]; BOARD_SIZE],
}

impl Board {
    // オセロの盤面を初期化する関数
    fn new() -> Board {
        let mut board = [[Stone::None; BOARD_SIZE]; BOARD_SIZE];
        board[3][3] = Stone::White;
        board[3][4] = Stone::Black;
        board[4][3] = Stone::Black;
        board[4][4] = Stone::White;
        Board { board }
    }

    // オセロの盤面を表示する関数
    fn print(&self) {
        for i in 0..BOARD_SIZE {
            for j in 0..BOARD_SIZE {
                match self.board[i][j] {
                    Stone::Black => print!(" ⚪︎ "),
                    Stone::White => print!(" ⚫︎ "),
                    Stone::None => print!("({}{})", j, i),
                }
            }
            println!();
        }
    }
}

// オセロの石を置く関数
impl Board {
    fn put(&mut self, x: usize, y: usize, stone: Stone) {
        if x < BOARD_SIZE && y < BOARD_SIZE {
            self.board[y][x] = stone;
        }
    }
}

// オセロの石をひっくり返す関数
impl Board {
    fn reverse(&mut self, x: usize, y: usize, stone: Stone) {
        let mut reverse = Vec::new();
        for dx in -1..=1 {
            for dy in -1..=1 {
                if dx == 0 && dy == 0 {
                    continue;
                }
                let mut x = x as i32;
                let mut y = y as i32;
                let mut tmp = Vec::new();
                loop {
                    x += dx;
                    y += dy;
                    if x < 0 || x >= BOARD_SIZE as i32 || y < 0 || y >= BOARD_SIZE as i32 {
                        break;
                    }
                    match self.board[y as usize][x as usize] {
                        Stone::None => break,
                        s if s == stone => {
                            reverse.append(&mut tmp);
                            break;
                        }
                        _ => tmp.push((x as usize, y as usize)),
                    }
                }
            }
        }
        for (x, y) in reverse {
            self.board[y][x] = stone;
        }
    }
}

Discussion