game is playable through netcat
This commit is contained in:
parent
14032202a6
commit
016b3aa6cf
5 changed files with 99 additions and 61 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -48,6 +48,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
name = "connect4"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bytes = "1.7.2"
|
||||
tokio = { version = "1.38.0", features = [
|
||||
"rt-multi-thread",
|
||||
"macros",
|
||||
|
|
|
@ -118,22 +118,25 @@ impl GameState {
|
|||
return score;
|
||||
}
|
||||
|
||||
pub fn display(&self) {
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut string = String::new();
|
||||
for irow in (0..NROWS).rev() {
|
||||
print!("\n ");
|
||||
string += " ";
|
||||
for icol in 0..NCOLS {
|
||||
let idx = irow + 7 * icol;
|
||||
|
||||
if (self.bitboards[0] >> idx) & 1 != 0 {
|
||||
print!("● ");
|
||||
string += "● ";
|
||||
} else if (self.bitboards[1] >> idx) & 1 != 0 {
|
||||
print!("○ ");
|
||||
string += "○ ";
|
||||
} else {
|
||||
print!("· ");
|
||||
string += "· ";
|
||||
}
|
||||
}
|
||||
string += "\n";
|
||||
}
|
||||
print!("\n 1 2 3 4 5 6 7\n\n");
|
||||
string += " 1 2 3 4 5 6 7\n\n";
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,31 +1,89 @@
|
|||
|
||||
use std::f32::consts::E;
|
||||
use bytes::BytesMut;
|
||||
|
||||
use tokio::{
|
||||
// AsyncWriteExt trait provides asynchronous write methods like write_all
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
net::{TcpListener, TcpStream},
|
||||
net::TcpStream,
|
||||
};
|
||||
|
||||
use crate::connect4::GameState;
|
||||
|
||||
/// The Server struct holds the tokio TcpListener which listens for
|
||||
/// incoming TCP connections.
|
||||
use crate::connect4;
|
||||
#[derive(Debug)]
|
||||
pub struct GameServer {
|
||||
}
|
||||
pub struct GameServer {}
|
||||
|
||||
impl GameServer {
|
||||
pub async fn handle(socket: &mut TcpStream, game_state: GameState) {
|
||||
match socket.write_all("Hello!!".as_bytes()).await {
|
||||
Ok(_) => {println!("socket socketed successfully")},
|
||||
Err(e) => {println!("socket didn't socket: {e}")},
|
||||
}
|
||||
loop {
|
||||
match socket.read_i8().await {
|
||||
Ok(read) => {println!("read: {read}")},
|
||||
Err(_) => {break},
|
||||
pub async fn handle(socket: &mut TcpStream) -> Result<(), String> {
|
||||
send_text("Connect 4\nChoose your difficulty [1-9]: ", socket).await?;
|
||||
|
||||
let depth = get_one_char(b"123456789", socket).await? - b'0';
|
||||
|
||||
println!("Difficulty: {depth}");
|
||||
|
||||
let mut board = connect4::GameState::new();
|
||||
|
||||
let mut end_score: i64 = -1;
|
||||
|
||||
while end_score == -1 {
|
||||
|
||||
match board.counter % 2 == 0 {
|
||||
true => {
|
||||
send_text(format!("Move {}:\n", board.counter).as_str(), socket).await?;
|
||||
send_text(board.to_string().as_str(), socket).await?;
|
||||
|
||||
send_text("Choose column: ", socket).await?;
|
||||
let mut player_move = get_one_char(b"1234567", socket).await? - b'0';
|
||||
while !board.move_is_valid((player_move - 1).into()) {
|
||||
send_text("Illegal move.\nChoose column: ", socket).await?;
|
||||
player_move = get_one_char(b"1234567", socket).await? - b'0';
|
||||
}
|
||||
|
||||
board.make_move((player_move - 1).into());
|
||||
end_score = board.end_state_reached();
|
||||
send_text("\n", socket).await?;
|
||||
},
|
||||
false => {
|
||||
let best_move = connect4::get_minimax_move(&mut board, depth.into());
|
||||
|
||||
board.make_move(best_move);
|
||||
end_score = board.end_state_reached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if end_score == 0 {
|
||||
send_text( "It's a Tie\n\n", socket).await?;
|
||||
} else if end_score > 0 {
|
||||
send_text("White (●) Won!\n\n", socket).await?;
|
||||
} else {
|
||||
send_text("Black (○) Won!\n\n", socket).await?;
|
||||
}
|
||||
|
||||
send_text(&board.to_string(), socket).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_one_char(allowed: &[u8], socket: &mut TcpStream) -> Result<u8, String> {
|
||||
let mut buffer = BytesMut::with_capacity(100);
|
||||
loop {
|
||||
match socket.read_buf(&mut buffer).await {
|
||||
Ok(0) => return Err(format!("socket disconnected")),
|
||||
Ok(read) => {
|
||||
println!("read {read} bytes: {:?}", buffer);
|
||||
for byte in &buffer {
|
||||
if allowed.contains(byte) {
|
||||
return Ok(*byte);
|
||||
}
|
||||
}
|
||||
buffer.clear();
|
||||
}
|
||||
Err(e) => return Err(format!("socket error while reading a digit: {e}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_text(text: &str, socket: &mut TcpStream) -> Result<(), String> {
|
||||
match socket.write_all(text.as_bytes()).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(format!("socket error while sending text: {e}")),
|
||||
}
|
||||
}
|
41
src/main.rs
41
src/main.rs
|
@ -1,4 +1,3 @@
|
|||
use connect4::GameState;
|
||||
use game_server::GameServer;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
|
@ -7,21 +6,20 @@ mod game_server;
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let addr = format!("127.0.0.1:{}", 6379);
|
||||
let addr = format!("127.0.0.1:{}", 1234);
|
||||
|
||||
let listener = match TcpListener::bind(&addr).await {
|
||||
Ok(tcp_listener) => {
|
||||
println!("TCP listener started on port 6379");
|
||||
tcp_listener
|
||||
}
|
||||
Err(e) => panic!("Could not bind the TCP listener to {}. Err: {}", &addr, e),
|
||||
};
|
||||
let listener = TcpListener::bind(&addr)
|
||||
.await
|
||||
.expect(format!("Could not bind the TCP listener to {}", &addr).as_str());
|
||||
|
||||
loop {
|
||||
match listener.accept().await {
|
||||
Ok((mut socket, _)) => {
|
||||
tokio::spawn(async move {
|
||||
GameServer::handle(&mut socket, GameState::new()).await;
|
||||
match GameServer::handle(&mut socket).await {
|
||||
Ok(_) => {println!("Game finished")},
|
||||
Err(e) => {println!("Game failed with error: {e}")},
|
||||
};
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
|
@ -30,28 +28,5 @@ async fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
let mut board = connect4::GameState::new();
|
||||
let depth = 7;
|
||||
|
||||
let mut end_score: i64 = -1;
|
||||
|
||||
while end_score == -1 {
|
||||
println!("Move {}:", board.counter);
|
||||
board.display();
|
||||
let best_move = connect4::get_minimax_move(&mut board, depth);
|
||||
|
||||
board.make_move(best_move);
|
||||
end_score = board.end_state_reached();
|
||||
}
|
||||
|
||||
println!("Move {}:", board.counter);
|
||||
board.display();
|
||||
|
||||
if end_score == 0 {
|
||||
println!("It's a Tie");
|
||||
} else if end_score > 0 {
|
||||
println!("White (●) Won!");
|
||||
} else {
|
||||
println!("Black (○) Won!");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue