Skip to content
Snippets Groups Projects
Commit b145cc53 authored by sven.wikberg's avatar sven.wikberg
Browse files

propre af

parent 7af4fd4b
No related branches found
No related tags found
No related merge requests found
extern crate rust_hepia_lib;
const WIDTH: usize = 7;
const HEIGHT: usize = 6;
const RED_CHAR: char = 'X';
const YELLOW_CHAR: char = 'O';
#[derive(Copy, Clone, PartialEq)]
enum Connect4Case {
Empty,
Red,
Yellow,
}
pub struct Connect4 {
board: [[Connect4Case; WIDTH]; HEIGHT],
game_mode: u8,
turn_count: u32,
last_col_played: usize,
width: usize,
height: usize,
}
impl Connect4 {
pub fn new() -> Connect4 {
if WIDTH < 4 || HEIGHT < 4 {
panic!("The connect 4 board is too short (WIDTH and HEIGHT must be at least 4)");
}
Connect4 {
board: [[Connect4Case::Empty; WIDTH]; HEIGHT],
game_mode: 0,
turn_count: 0,
last_col_played: 0,
width: WIDTH,
height: HEIGHT,
}
}
fn get_max_turn(&self) -> u32 {
(self.width as u32 * self.height as u32)
}
fn is_red_turn(&self) -> bool {
if self.turn_count % 2 == 1 {
return true;
} else {
return false;
}
}
fn choose_game_mode() -> u8 {
let mut x: i32;
loop {
println!("Choose your game mode : (1) Player vs Player. (2) Player vs IA, easy. (3) Player vs IA, hard.");
x = rust_hepia_lib::read_int();
match x {
1 | 2 | 3 => return x as u8,
_ => println!("This is not a valid number"),
}
}
}
fn place_piece(&mut self, x: usize) -> bool {
if x >= self.width {
// si on veut placer une piece en dehors du tableau
return false;
}
if self.board[0 as usize][x] != Connect4Case::Empty {
// si la colonne est deja pleine
return false;
}
for i in 1..self.height {
if self.board[i][x] != Connect4Case::Empty {
// on place la nouelle piece au dessus de la plus haute piece de la colonne
self.board[i - 1][x] = if self.is_red_turn() {
Connect4Case::Red
} else {
Connect4Case::Yellow
};
return true;
}
}
self.board[self.height - 1][x] = if self.is_red_turn() {
// si la colonne est vide
Connect4Case::Red
} else {
Connect4Case::Yellow
};
return true;
}
fn choose_col(&self) -> usize {
let mut col: i32;
loop {
println!("Choose a column (1-{})", self.width);
col = rust_hepia_lib::read_int();
if col < 1 || col > self.width as i32 {
println!("This is not a valid column");
} else {
return (col - 1) as usize;
}
}
}
fn play_turn(&mut self) {
self.turn_count += 1;
println!(
"This is {}'s turn !!",
if self.is_red_turn() { RED_CHAR } else { YELLOW_CHAR }
);
if self.is_red_turn() || self.game_mode == 1 {
let mut col: usize;
loop {
col = self.choose_col();
if !self.place_piece(col) {
println!("This is not a valid column");
} else {
self.last_col_played = col;
break;
}
}
} else if self.game_mode == 2 {
let x: usize = self.get_ia1_play();
self.place_piece(x);
self.last_col_played = x;
} else if self.game_mode == 3 {
let x: usize = self.get_ia2_play();
self.place_piece(x);
self.last_col_played = x;
}
}
fn get_ia1_play(&self) -> usize {
let mut col: usize;
let mut last_emp: Option<usize> = None;
loop {
col = rust_hepia_lib::gen(0, self.width as i32) as usize;
last_emp = self.get_last_empty(col);
if last_emp.is_some() {
return col;
}
}
}
fn get_ia2_play(&self) -> usize {
let mut x: Option<usize> = None;
let mut block_col: usize;
let mut last_emp: Option<usize> = None;
for i in 0..self.width {
last_emp = self.get_last_empty(i);
if last_emp.is_some() {
let y = last_emp.unwrap();
for j in 0..4 {
if self.cnt_same_piece_line(i, y, Connect4Case::Yellow, j) >= 4 {
return i;
} else if self.cnt_same_piece_line(i, y, Connect4Case::Red, j) >= 4 {
x = Some(i);
block_col = i;
}
}
}
}
if let Some(block_col) = x { // c'est dans une option car il ne pourrait ne pas y avoir de case a bloqué
return block_col;
} else {
return self.get_ia1_play();
}
}
fn get_last_empty(&self, col: usize) -> Option<usize> {
if self.board[self.height - 1][col] == Connect4Case::Empty { return Some(self.height - 1); }
if self.board[0][col] != Connect4Case::Empty { return None; }
for i in 1..self.height {
if self.board[i][col] != Connect4Case::Empty { return Some(i - 1); }
}
None
}
fn display(&self) {
for y in 0..self.height {
if y == 0 {
print!("┌─");
for _x in 1..self.width {
print!("┬─");
}
println!("┐");
} else {
print!("├─");
for _x in 1..self.width {
print!("┼─");
}
println!("┤");
}
for x in 0..self.width {
print!(
"|{}",
match self.board[y][x] {
Connect4Case::Empty => ' ',
Connect4Case::Red => RED_CHAR,
Connect4Case::Yellow => YELLOW_CHAR,
}
);
if x + 1 == self.width {
print!("|");
}
}
println!();
}
print!("└─");
for _x in 1..self.width {
print!("┴─");
}
println!("┘");
for x in 1..self.width + 1 {
print!(" {0}", x);
}
println!();
}
/*fn is_won(&self) -> bool {
for y in 0..self.height {
for x in 0..self.width {
if self.board[y][x] != Connect4Case::Empty {
if x + 3 < WIDTH {
// verif horizontale
if self.board[y][x + 1] == self.board[y][x]
&& self.board[y][x + 2] == self.board[y][x]
&& self.board[y][x + 3] == self.board[y][x]
{
return true;
}
}
if y + 3 < HEIGHT {
// verif verticale
if self.board[y + 1][x] == self.board[y][x]
&& self.board[y + 2][x] == self.board[y][x]
&& self.board[y + 3][x] == self.board[y][x]
{
return true;
}
}
if x + 3 < WIDTH && y + 3 < HEIGHT {
// verif diagonale 1 : \
if self.board[y + 1][x + 1] == self.board[y][x]
&& self.board[y + 2][x + 2] == self.board[y][x]
&& self.board[y + 3][x + 3] == self.board[y][x]
{
return true;
}
}
if x >= 3 && y + 3 < HEIGHT {
// verif diagonale 2 : /
if self.board[y + 1][x - 1] == self.board[y][x]
&& self.board[y + 2][x - 2] == self.board[y][x]
&& self.board[y + 3][x - 3] == self.board[y][x]
{
return true;
}
}
}
}
}
return false;
}*/
fn is_full(&self) -> bool {
if self.turn_count >= self.get_max_turn() {
true
} else {
false
}
}
fn last_play_won(&self) -> bool {
let mut i: usize = 0;
loop {
if self.board[i][self.last_col_played as usize] == Connect4Case::Empty {
i += 1;
} else {
break;
}
}
for j in 0..4 {
if self.cnt_same_piece_line(
self.last_col_played as usize,
i,
if self.is_red_turn() {
Connect4Case::Red
} else {
Connect4Case::Yellow
},
j,
) >= 4
{
return true;
}
}
false
}
fn cnt_same_piece_line(&self, x: usize, y: usize, c: Connect4Case, dir: u8) -> u32 {
let i: u32;
i = self.cnt_same_piece_dir(x, y, c, dir)
+ self.cnt_same_piece_dir(x, y, c, (dir + 4) % 8)
+ 1;
i
}
fn cnt_same_piece_dir(&self, x: usize, y: usize, c: Connect4Case, dir: u8) -> u32 {
match dir {
0 => if y != 0 && self.board[y - 1][x] == c {
//north
return self.cnt_same_piece_dir(x, y - 1, c, dir) + 1;
},
1 => if x != self.width - 1 && y != 0 && self.board[y - 1][x + 1] == c {
//north-west
return self.cnt_same_piece_dir(x + 1, y - 1, c, dir) + 1;
},
2 => if x != self.width - 1 && self.board[y][x + 1] == c {
//west
return self.cnt_same_piece_dir(x + 1, y, c, dir) + 1;
},
3 => if x != self.width - 1 && y != self.height - 1 && self.board[y + 1][x + 1] == c {
//south-west
return self.cnt_same_piece_dir(x + 1, y + 1, c, dir) + 1;
},
4 => if y < self.height - 1 && self.board[y + 1][x] == c {
//south
return self.cnt_same_piece_dir(x, y + 1, c, dir) + 1;
},
5 => if x != 0 && y != self.height - 1 && self.board[y + 1][x - 1] == c {
//south-east
return self.cnt_same_piece_dir(x - 1, y + 1, c, dir) + 1;
},
6 => if x != 0 && self.board[y][x - 1] == c {
//east
return self.cnt_same_piece_dir(x - 1, y, c, dir) + 1;
},
7 => if x != 0 && y != 0 && self.board[y - 1][x - 1] == c {
//north-east
return self.cnt_same_piece_dir(x - 1, y - 1, c, dir) + 1;
},
_ => panic!{"Direction not valid"},
}
return 0;
}
pub fn play_game(&mut self) {
self.game_mode = Connect4::choose_game_mode();
self.display();
loop {
self.play_turn();
self.display();
if self.last_play_won() {
if self.is_red_turn() {
println!("O won GG !");
} else {
println!("X won, well played !");
}
break;
}
if self.is_full() {
println!("Draw, nobody won !");
break;
}
}
}
}
\ No newline at end of file
extern crate rust_hepia_lib; extern crate tp5_connect4;
const WIDTH: usize = 7; use tp5_connect4::Connect4;
const HEIGHT: usize = 6;
const RED_CHAR: char = 'X';
const YELLOW_CHAR: char = 'O';
#[derive(Copy, Clone, PartialEq)]
enum Connect4Case {
Empty,
Red,
Yellow,
}
struct Connect4 {
board: [[Connect4Case; WIDTH]; HEIGHT],
game_mode: u8,
turn_count: u32,
last_col_played: usize,
width: usize,
height: usize,
}
impl Connect4 {
fn new() -> Connect4 {
if WIDTH < 4 || HEIGHT < 4 {
panic!("The connect 4 board is too short (WIDTH and HEIGHT must be at least 4)");
}
Connect4 {
board: [[Connect4Case::Empty; WIDTH]; HEIGHT],
game_mode: 0,
turn_count: 0,
last_col_played: 0,
width: WIDTH,
height: HEIGHT,
}
}
fn get_max_turn(&self) -> u32 {
(self.width as u32 * self.height as u32)
}
fn is_red_turn(&self) -> bool {
if self.turn_count % 2 == 1 {
return true;
} else {
return false;
}
}
fn choose_game_mode() -> u8 {
let mut x: i32;
loop {
println!("Choose your game mode : (1) Player vs Player. (2) Player vs IA, easy. (3) Player vs IA, hard.");
x = rust_hepia_lib::read_int();
match x {
1 | 2 | 3 => return x as u8,
_ => println!("This is not a valid number"),
}
}
}
fn place_piece(&mut self, x: usize) -> bool {
if x >= self.width {
// si on veut placer une piece en dehors du tableau
return false;
}
if self.board[0 as usize][x] != Connect4Case::Empty {
// si la colonne est deja pleine
return false;
}
for i in 1..self.height {
if self.board[i][x] != Connect4Case::Empty {
// on place la nouelle piece au dessus de la plus haute piece de la colonne
self.board[i - 1][x] = if self.is_red_turn() {
Connect4Case::Red
} else {
Connect4Case::Yellow
};
return true;
}
}
self.board[self.height - 1][x] = if self.is_red_turn() {
// si la colonne est vide
Connect4Case::Red
} else {
Connect4Case::Yellow
};
return true;
}
fn choose_col(&self) -> usize {
let mut col: i32;
loop {
println!("Choose a column (1-{})", self.width);
col = rust_hepia_lib::read_int();
if col < 1 || col > self.width as i32 {
println!("This is not a valid column");
} else {
return (col - 1) as usize;
}
}
}
fn play_turn(&mut self) {
self.turn_count += 1;
println!(
"This is {}'s turn !!",
if self.is_red_turn() { RED_CHAR } else { YELLOW_CHAR }
);
if self.is_red_turn() || self.game_mode == 1 {
let mut col: usize;
loop {
col = self.choose_col();
if !self.place_piece(col) {
println!("This is not a valid column");
} else {
self.last_col_played = col;
break;
}
}
} else if self.game_mode == 2 {
let x: usize = self.get_ia1_play();
self.place_piece(x);
self.last_col_played = x;
} else if self.game_mode == 3 {
let x: usize = self.get_ia2_play();
self.place_piece(x);
self.last_col_played = x;
}
}
fn get_ia1_play(&self) -> usize {
let mut col: usize;
let mut last_emp: Option<usize> = None;
loop {
col = rust_hepia_lib::gen(0, self.width as i32) as usize;
last_emp = self.get_last_empty(col);
if last_emp.is_some() {
return col;
}
}
}
fn get_ia2_play(&self) -> usize {
let mut x: Option<usize> = None;
let mut block_col: usize;
let mut last_emp: Option<usize> = None;
for i in 0..self.width {
last_emp = self.get_last_empty(i);
if last_emp.is_some() {
let y = last_emp.unwrap();
for j in 0..4 {
if self.cnt_same_piece_line(i, y, Connect4Case::Yellow, j) >= 4 {
return i;
} else if self.cnt_same_piece_line(i, y, Connect4Case::Red, j) >= 4 {
x = Some(i);
block_col = i;
}
}
}
}
if let Some(block_col) = x {
return block_col;
} else {
return self.get_ia1_play();
}
}
fn get_last_empty(&self, col: usize) -> Option<usize> {
if self.board[self.height - 1][col] == Connect4Case::Empty { return Some(self.height - 1); }
if self.board[0][col] != Connect4Case::Empty { return None; }
for i in 1..self.height {
if self.board[i][col] != Connect4Case::Empty { return Some(i - 1); }
}
None
}
fn display(&self) {
for y in 0..self.height {
if y == 0 {
print!("┌─");
for _x in 1..self.width {
print!("┬─");
}
println!("┐");
} else {
print!("├─");
for _x in 1..self.width {
print!("┼─");
}
println!("┤");
}
for x in 0..self.width {
print!(
"|{}",
match self.board[y][x] {
Connect4Case::Empty => ' ',
Connect4Case::Red => RED_CHAR,
Connect4Case::Yellow => YELLOW_CHAR,
}
);
if x + 1 == self.width {
print!("|");
}
}
println!();
}
print!("└─");
for _x in 1..self.width {
print!("┴─");
}
println!("┘");
for x in 1..self.width + 1 {
print!(" {0}", x);
}
println!();
}
/*fn is_won(&self) -> bool {
for y in 0..self.height {
for x in 0..self.width {
if self.board[y][x] != Connect4Case::Empty {
if x + 3 < WIDTH {
// verif horizontale
if self.board[y][x + 1] == self.board[y][x]
&& self.board[y][x + 2] == self.board[y][x]
&& self.board[y][x + 3] == self.board[y][x]
{
return true;
}
}
if y + 3 < HEIGHT {
// verif verticale
if self.board[y + 1][x] == self.board[y][x]
&& self.board[y + 2][x] == self.board[y][x]
&& self.board[y + 3][x] == self.board[y][x]
{
return true;
}
}
if x + 3 < WIDTH && y + 3 < HEIGHT {
// verif diagonale 1 : \
if self.board[y + 1][x + 1] == self.board[y][x]
&& self.board[y + 2][x + 2] == self.board[y][x]
&& self.board[y + 3][x + 3] == self.board[y][x]
{
return true;
}
}
if x >= 3 && y + 3 < HEIGHT {
// verif diagonale 2 : /
if self.board[y + 1][x - 1] == self.board[y][x]
&& self.board[y + 2][x - 2] == self.board[y][x]
&& self.board[y + 3][x - 3] == self.board[y][x]
{
return true;
}
}
}
}
}
return false;
}*/
fn is_full(&self) -> bool {
if self.turn_count >= self.get_max_turn() {
true
} else {
false
}
}
fn last_play_won(&self) -> bool {
let mut i: usize = 0;
loop {
if self.board[i][self.last_col_played as usize] == Connect4Case::Empty {
i += 1;
} else {
break;
}
}
for j in 0..4 {
if self.cnt_same_piece_line(
self.last_col_played as usize,
i,
if self.is_red_turn() {
Connect4Case::Red
} else {
Connect4Case::Yellow
},
j,
) >= 4
{
return true;
}
}
false
}
fn cnt_same_piece_line(&self, x: usize, y: usize, c: Connect4Case, dir: u8) -> u32 {
let i: u32;
i = self.cnt_same_piece_dir(x, y, c, dir)
+ self.cnt_same_piece_dir(x, y, c, (dir + 4) % 8)
+ 1;
i
}
fn cnt_same_piece_dir(&self, x: usize, y: usize, c: Connect4Case, dir: u8) -> u32 {
match dir {
0 => if y != 0 && self.board[y - 1][x] == c {
//north
return self.cnt_same_piece_dir(x, y - 1, c, dir) + 1;
},
1 => if x != self.width - 1 && y != 0 && self.board[y - 1][x + 1] == c {
//north-west
return self.cnt_same_piece_dir(x + 1, y - 1, c, dir) + 1;
},
2 => if x != self.width - 1 && self.board[y][x + 1] == c {
//west
return self.cnt_same_piece_dir(x + 1, y, c, dir) + 1;
},
3 => if x != self.width - 1 && y != self.height - 1 && self.board[y + 1][x + 1] == c {
//south-west
return self.cnt_same_piece_dir(x + 1, y + 1, c, dir) + 1;
},
4 => if y < self.height - 1 && self.board[y + 1][x] == c {
//south
return self.cnt_same_piece_dir(x, y + 1, c, dir) + 1;
},
5 => if x != 0 && y != self.height - 1 && self.board[y + 1][x - 1] == c {
//south-east
return self.cnt_same_piece_dir(x - 1, y + 1, c, dir) + 1;
},
6 => if x != 0 && self.board[y][x - 1] == c {
//east
return self.cnt_same_piece_dir(x - 1, y, c, dir) + 1;
},
7 => if x != 0 && y != 0 && self.board[y - 1][x - 1] == c {
//north-east
return self.cnt_same_piece_dir(x - 1, y - 1, c, dir) + 1;
},
_ => panic!{"Direction not valid"},
}
return 0;
}
fn play_game(&mut self) {
self.game_mode = Connect4::choose_game_mode();
self.display();
loop {
self.play_turn();
self.display();
if self.last_play_won() {
if self.is_red_turn() {
println!("O won GG !");
} else {
println!("X won, well played !");
}
break;
}
if self.is_full() {
println!("Draw, nobody won !");
break;
}
}
}
}
fn main() { fn main() {
let mut c: Connect4 = Connect4::new(); let mut c: Connect4 = Connect4::new();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment