差分
このページの2つのバージョン間の差分を表示します。
| 両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン | ||
| youtube:egui-tictactoe [2024/02/28 18:26] – 削除 - 外部編集 (不明な日付) 127.0.0.1 | youtube:egui-tictactoe [2024/02/29 11:49] (現在) – freemikan | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| + | ====== 三並べ (Tic-Tac-Toe) ====== | ||
| + | 作成日: 2022-12-14 (水) | ||
| + | |||
| + | {{: | ||
| + | |||
| + | ===== src/main.rs ===== | ||
| + | |||
| + | |||
| + | <file rust> | ||
| + | use eframe:: | ||
| + | |||
| + | fn main() { | ||
| + | let options = eframe:: | ||
| + | initial_window_size: | ||
| + | ..Default:: | ||
| + | }; | ||
| + | eframe:: | ||
| + | " | ||
| + | options, | ||
| + | Box:: | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | struct MyApp { | ||
| + | turn: Player, | ||
| + | pieces: Vec< | ||
| + | square_size: | ||
| + | } | ||
| + | |||
| + | impl Default for MyApp { | ||
| + | fn default() -> Self { | ||
| + | Self { | ||
| + | turn: Player::O, | ||
| + | pieces: Vec::new(), | ||
| + | square_size: | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | impl eframe::App for MyApp { | ||
| + | fn update(& | ||
| + | let winner = winner(& | ||
| + | let draw_match = self.pieces.len() == 9 && winner == None; | ||
| + | |||
| + | if winner == None && !draw_match { | ||
| + | // step the game | ||
| + | if let Some(pos) = self.clicked_position(ctx) { | ||
| + | let board_pos = egui::pos2( | ||
| + | (pos.x / self.square_size).floor(), | ||
| + | (pos.y / self.square_size).floor(), | ||
| + | ); | ||
| + | |||
| + | let open_square = self.pieces.iter().all(|p| { | ||
| + | p.place.x as i32 != board_pos.x as i32 || p.place.y as i32 != board_pos.y as i32 | ||
| + | }); | ||
| + | let on_board = board_pos.x >= 0.0 | ||
| + | && board_pos.x <= 2.0 | ||
| + | && board_pos.y >= 0.0 | ||
| + | && board_pos.y <= 2.0; | ||
| + | |||
| + | if open_square && on_board { | ||
| + | self.pieces.push(Piece { | ||
| + | player: self.turn, | ||
| + | place: board_pos, | ||
| + | }); | ||
| + | |||
| + | // next turn | ||
| + | self.turn = if self.turn == Player::O { | ||
| + | Player::X | ||
| + | } else { | ||
| + | Player::O | ||
| + | }; | ||
| + | } | ||
| + | } | ||
| + | } else { | ||
| + | // wait for right button clicked to restart the game | ||
| + | if ctx.input().pointer.secondary_clicked() { | ||
| + | *self = Default:: | ||
| + | } | ||
| + | } | ||
| + | |||
| + | egui:: | ||
| + | self.draw_board(ui.painter(), | ||
| + | self.draw_pieces(ui.painter(), | ||
| + | |||
| + | if let Some(player_wins) = winner { | ||
| + | self.draw_winner(ui.painter(), | ||
| + | } | ||
| + | |||
| + | if draw_match { | ||
| + | self.draw_draw_match(ui.painter()); | ||
| + | } | ||
| + | }); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | impl MyApp { | ||
| + | fn clicked_position(& | ||
| + | // avoid dead lock | ||
| + | // [[https:// | ||
| + | if let Some(pos) = { ctx.input().pointer.hover_pos() } { | ||
| + | if ctx.input().pointer.any_click() { | ||
| + | return Some(pos); | ||
| + | } | ||
| + | } | ||
| + | None | ||
| + | } | ||
| + | |||
| + | fn draw_board(& | ||
| + | for i in 0..3 { | ||
| + | for j in 0..3 { | ||
| + | let rect = egui:: | ||
| + | egui:: | ||
| + | egui:: | ||
| + | ); | ||
| + | let rounding = 0.0; | ||
| + | let color = egui:: | ||
| + | let stroke = egui:: | ||
| + | painter.rect(rect, | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | fn draw_pieces(& | ||
| + | for piece in & | ||
| + | piece.draw(painter, | ||
| + | } | ||
| + | } | ||
| + | |||
| + | fn draw_winner(& | ||
| + | painter.text( | ||
| + | painter.clip_rect().center(), | ||
| + | egui:: | ||
| + | format!( | ||
| + | " | ||
| + | if winner == Player::O { " | ||
| + | ), | ||
| + | egui:: | ||
| + | egui:: | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | fn draw_draw_match(& | ||
| + | painter.text( | ||
| + | painter.clip_rect().center(), | ||
| + | egui:: | ||
| + | " | ||
| + | egui:: | ||
| + | egui:: | ||
| + | ); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | # | ||
| + | enum Player { | ||
| + | O, | ||
| + | X, | ||
| + | } | ||
| + | |||
| + | struct Piece { | ||
| + | player: Player, | ||
| + | place: egui::Pos2, | ||
| + | } | ||
| + | |||
| + | impl Piece { | ||
| + | fn draw(& | ||
| + | let p = egui:: | ||
| + | match self.player { | ||
| + | Player::O => { | ||
| + | painter.circle_stroke( | ||
| + | egui:: | ||
| + | square_size * 0.3, | ||
| + | (3.0, egui:: | ||
| + | ); | ||
| + | } | ||
| + | Player::X => { | ||
| + | painter.line_segment( | ||
| + | [ | ||
| + | egui:: | ||
| + | egui:: | ||
| + | ], | ||
| + | (3.0, egui:: | ||
| + | ); | ||
| + | painter.line_segment( | ||
| + | [ | ||
| + | egui:: | ||
| + | egui:: | ||
| + | ], | ||
| + | (3.0, egui:: | ||
| + | ); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | fn winner(pieces: | ||
| + | for player in [Player::O, Player::X] { | ||
| + | for i in 0..3 { | ||
| + | if 3 == pieces | ||
| + | .iter() | ||
| + | .filter(|p| p.player == player) | ||
| + | .filter(|p| p.place.x as i32 == i) | ||
| + | .count() | ||
| + | { | ||
| + | return Some(player); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | for i in 0..3 { | ||
| + | if 3 == pieces | ||
| + | .iter() | ||
| + | .filter(|p| p.player == player) | ||
| + | .filter(|p| p.place.y as i32 == i) | ||
| + | .count() | ||
| + | { | ||
| + | return Some(player); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | if 3 == pieces | ||
| + | .iter() | ||
| + | .filter(|p| p.player == player) | ||
| + | .filter(|p| p.place.x as i32 == p.place.y as i32) | ||
| + | .count() | ||
| + | { | ||
| + | return Some(player); | ||
| + | } | ||
| + | |||
| + | if 3 == pieces | ||
| + | .iter() | ||
| + | .filter(|p| p.player == player) | ||
| + | .filter(|p| 2 - p.place.x as i32 == p.place.y as i32) | ||
| + | .count() | ||
| + | { | ||
| + | return Some(player); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | None | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Cargo.toml ===== | ||
| + | |||
| + | |||
| + | < | ||
| + | [package] | ||
| + | name = " | ||
| + | version = " | ||
| + | edition = " | ||
| + | |||
| + | # See more keys and their definitions at https:// | ||
| + | |||
| + | [dependencies] | ||
| + | eframe = " | ||
| + | </ | ||
