Skip to content
Snippets Groups Projects
Commit 863433b8 authored by Fabio Vandewaeter's avatar Fabio Vandewaeter
Browse files

readme

parent b6892148
No related branches found
No related tags found
No related merge requests found
......@@ -356,3 +356,236 @@ where
}
```
# 3. Long exercise proposal
```rs
trait Game {
type Move;
type Player: std::fmt::Debug;
fn current_player(&self) -> Self::Player;
fn is_over(&self) -> bool;
fn make_move(&mut self, mv: Self::Move) -> Result<(), String>;
fn display(&self);
fn parse_move(input: &str) -> Result<Self::Move, String>;
}
```
```rs
#[derive(Clone, Copy, Debug, PartialEq)]
enum TicTacToePlayer {
X,
O,
}
struct TicTacToe {
board: [Option<TicTacToePlayer>; 9],
current_player: TicTacToePlayer,
}
impl TicTacToe {
fn new() -> Self {
Self {
board: [None; 9],
current_player: TicTacToePlayer::X,
}
}
}
impl Game for TicTacToe {
type Move = (usize, usize);
type Player = TicTacToePlayer;
fn current_player(&self) -> Self::Player {
self.current_player
}
fn is_over(&self) -> bool {
let b = &self.board;
// Check rows.
for i in 0..3 {
if let Some(p) = b[i * 3] {
if b[i * 3 + 1] == Some(p) && b[i * 3 + 2] == Some(p) {
return true;
}
}
}
// Check columns.
for j in 0..3 {
if let Some(p) = b[j] {
if b[j + 3] == Some(p) && b[j + 6] == Some(p) {
return true;
}
}
}
// Check diagonals.
if let Some(p) = b[0] {
if b[4] == Some(p) && b[8] == Some(p) {
return true;
}
}
if let Some(p) = b[2] {
if b[4] == Some(p) && b[6] == Some(p) {
return true;
}
}
// Game is over if board is full.
if b.iter().all(|&cell| cell.is_some()) {
return true;
}
false
}
fn make_move(&mut self, mv: Self::Move) -> Result<(), String> {
let (row, col) = mv;
if row >= 3 || col >= 3 {
return Err("Move out of bounds".to_string());
}
let idx = row * 3 + col;
if self.board[idx].is_some() {
return Err("Cell already occupied".to_string());
}
self.board[idx] = Some(self.current_player);
// Switch player.
self.current_player = match self.current_player {
TicTacToePlayer::X => TicTacToePlayer::O,
TicTacToePlayer::O => TicTacToePlayer::X,
};
Ok(())
}
fn display(&self) {
println!("Current board:");
for row in 0..3 {
for col in 0..3 {
let idx = row * 3 + col;
let symbol = match self.board[idx] {
Some(TicTacToePlayer::X) => "X",
Some(TicTacToePlayer::O) => "O",
None => ".",
};
print!("{} ", symbol);
}
println!();
}
}
fn parse_move(input: &str) -> Result<Self::Move, String> {
// Expect two numbers separated by whitespace (e.g., "0 1")
let parts: Vec<&str> = input.split_whitespace().collect();
if parts.len() != 2 {
return Err("Please enter two numbers separated by space".to_string());
}
let row = parts[0]
.parse::<usize>()
.map_err(|_| "Invalid row".to_string())?;
let col = parts[1]
.parse::<usize>()
.map_err(|_| "Invalid column".to_string())?;
Ok((row, col))
}
}
```
```rs
#[derive(Clone, Copy, Debug, PartialEq)]
enum NimGamePlayer {
First,
Second,
}
struct NimGame {
stones: u32,
current_player: NimGamePlayer,
}
impl NimGame {
fn new(stones: u32) -> Self {
Self {
stones: stones,
current_player: NimGamePlayer::First,
}
}
}
impl Game for NimGame {
type Move = u32;
type Player = NimGamePlayer;
fn current_player(&self) -> Self::Player {
self.current_player
}
fn is_over(&self) -> bool {
self.stones == 0
}
fn make_move(&mut self, mv: Self::Move) -> Result<(), String> {
if mv < 1 || mv > 2 {
return Err("You can only remove 1 or 2 stones".to_string());
}
if mv > self.stones {
return Err("Not enough stones remaining".to_string());
}
self.stones -= mv;
self.current_player = match self.current_player {
NimGamePlayer::First => NimGamePlayer::Second,
NimGamePlayer::Second => NimGamePlayer::First,
};
Ok(())
}
fn display(&self) {
println!("Stones remaining: {}", self.stones);
}
fn parse_move(input: &str) -> Result<Self::Move, String> {
input
.trim()
.parse::<u32>()
.map_err(|_| "Invalid number".to_string())
}
}
```
```rs
fn play_game<G: Game>(mut game: G) {
while !game.is_over() {
game.display();
print!("Player {:?}, enter your move: ", game.current_player());
std::io::stdout().flush().unwrap();
let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.expect("Failed to read input");
match G::parse_move(input.trim()) {
Ok(mv) => {
if let Err(e) = game.make_move(mv) {
println!("Error: {}", e);
}
}
Err(e) => println!("Invalid move: {}", e),
}
}
println!("Game over!");
game.display();
}
```
```rs
fn main() {
println!("\n--- Game engine demo ---");
let mut choice = String::new();
println!("\n--- Select game ---");
println!("1: Tic Tac Toe");
println!("2: Nim Game");
let mut game_choice = String::new();
std::io::stdin().read_line(&mut game_choice).unwrap();
match game_choice.trim() {
"1" => {
let game = TicTacToe::new();
play_game(game);
}
"2" => {
println!("Enter initial number of stones:");
let mut stones_str = String::new();
std::io::stdin().read_line(&mut stones_str).unwrap();
let stones = stones_str.trim().parse::<u32>().unwrap_or(10);
let game = NimGame::new(stones);
play_game(game);
}
_ => println!("Invalid game choice"),
}
}
```
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment