From 22c4ba5bc127c19f8515ce2101c2e09a28a86e4e Mon Sep 17 00:00:00 2001 From: Uncle Scientist Date: Thu, 26 Mar 2026 08:20:29 -0400 Subject: [PATCH] Add Rust port of 40_Gomoku --- 40_Gomoko/rust/Cargo.lock | 411 +++++++++++++++++++++++++++++++++++++ 40_Gomoko/rust/Cargo.toml | 7 + 40_Gomoko/rust/src/main.rs | 209 +++++++++++++++++++ 3 files changed, 627 insertions(+) create mode 100644 40_Gomoko/rust/Cargo.lock create mode 100644 40_Gomoko/rust/Cargo.toml create mode 100644 40_Gomoko/rust/src/main.rs diff --git a/40_Gomoko/rust/Cargo.lock b/40_Gomoko/rust/Cargo.lock new file mode 100644 index 000000000..7ef3861c9 --- /dev/null +++ b/40_Gomoko/rust/Cargo.lock @@ -0,0 +1,411 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core", + "wasip2", + "wasip3", +] + +[[package]] +name = "gomoku" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +dependencies = [ + "chacha20", + "getrandom", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/40_Gomoko/rust/Cargo.toml b/40_Gomoko/rust/Cargo.toml new file mode 100644 index 000000000..6874f0e90 --- /dev/null +++ b/40_Gomoko/rust/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "gomoku" +version = "0.1.0" +edition = "2024" + +[dependencies] +rand = "0.10.0" diff --git a/40_Gomoko/rust/src/main.rs b/40_Gomoko/rust/src/main.rs new file mode 100644 index 000000000..53ec70ae9 --- /dev/null +++ b/40_Gomoko/rust/src/main.rs @@ -0,0 +1,209 @@ +use std::{ + fmt::Display, + io::{BufRead, Write}, +}; + +use rand::prelude::*; + +fn main() { + println!("{:>33}GOMOKU", ""); + println!("{:>15}CREATIVE COMPUTING MORISSTOWN, NEW JERSEY\n\n\n", ""); + + println!("Welcome to the oriental game of Gomoku."); + println!("\nThe game is played on an N by N grid of a size"); + println!("that you specify. During your play, you may cover one grid"); + println!("intersection with a marker. The object of the game is to get"); + println!("5 adjacent markers in a row -- horizontally, vertically, or"); + println!("diagonally. On the board diagram, your moves are marked"); + println!("with a '1' and the computer moves with a '2'."); + println!("\nThe computer does not keep track of who has won."); + println!("To end the game, type -1,-1 for your move.\n"); + + loop { + let size = get_board_size(); + + // Line 210: initialize the game board + let mut game = Gomoku::new(size); + + if !game.play() { + break; + } + } +} + +struct Gomoku { + board: Vec>, + size: isize, +} + +impl Gomoku { + fn new(size: usize) -> Self { + Self { + board: vec![vec![Piece::Empty; size]; size], + size: size as isize, + } + } + + fn get_player_move(&self) -> (isize, isize) { + let mut first_attempt = true; + loop { + if !first_attempt { + println!("Illegal move. Try again..."); + } + first_attempt = false; + let response = prompt_for_input("Your play (I,J)"); + let Some((i, j)) = response.split_once(',') else { + continue; + }; + let Ok(i) = i.trim().parse::() else { + continue; + }; + let Ok(j) = j.trim().parse::() else { + continue; + }; + if i == -1 { + return (-1, -1); + } + if i < 1 || i > self.size || j < 1 || j > self.size { + continue; + } + return (i, j); + } + } + + fn play(&mut self) -> bool { + let mut rng = rand::rng(); + + // Line 300 + println!("\nWe alternate moves. You go first...\n"); + + 'next_move: loop { + println!("{self}"); + + // Line 310 + let (i, j) = self.get_player_move(); + + // Line 320 + if i == -1 { + break; + } + + let pos = self.get(i, j); + + match *pos { + Piece::Empty => *pos = Piece::Human, + Piece::Computer | Piece::Human => { + println!("Square occupied. Try again..."); + continue; + } + } + + // Lines 500-590: The computer tries an intelligent move + for e in -1..=1 { + for f in -1..=1 { + // Line 510: + if e == 0 && f == 0 { + continue; + } + + // Line 540: + let x = i + e; + let y = j + f; + if x < 1 || x > self.size || y < 1 || y > self.size { + continue; + } + + let pos = self.get(x, y); + if *pos == Piece::Human { + let x = i - e; + let y = j - f; + if x < 1 || x > self.size || y < 1 || y > self.size { + continue; + } + let pos = self.get(x, y); + if *pos == Piece::Empty { + *pos = Piece::Computer; + continue 'next_move; + } + } + } + } + + // Lines 600-660: The computer tries a random move + loop { + let x = rng.random_range(1..=self.size as usize) as isize; + let y = rng.random_range(1..=self.size as usize) as isize; + let pos = self.get(x, y); + if *pos == Piece::Empty { + *pos = Piece::Computer; + continue 'next_move; + } + } + } + + // Lines 980-999 + println!("\nThanks for the game!!"); + prompt_for_input("Play again (1 for yes, 0 for no)") == "1" + } + + fn get(&mut self, i: isize, j: isize) -> &mut Piece { + &mut self.board[i as usize - 1][j as usize - 1] + } +} + +impl Display for Gomoku { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for row in &self.board { + for col in row { + write!(f, "{col}")?; + } + writeln!(f)?; + } + Ok(()) + } +} + +#[derive(Clone, Copy, PartialEq)] +enum Piece { + Empty, + Computer, + Human, +} + +impl Display for Piece { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + " {}", + match self { + Piece::Empty => '0', + Piece::Computer => '2', + Piece::Human => '1', + } + ) + } +} + +fn prompt_for_input>(prompt: S) -> String { + print!("{}? ", prompt.as_ref()); + let mut lock = std::io::stdout().lock(); + let _ = lock.flush(); + + let mut buffer = String::new(); + let stdin = std::io::stdin(); + let mut handle = stdin.lock(); + let _ = handle.read_line(&mut buffer); + buffer.trim().to_string() +} + +fn get_board_size() -> usize { + loop { + let buffer = prompt_for_input("What is your board size (min 7/ max 19)"); + if let Ok(val) = buffer.trim().parse::() + && (7..=19).contains(&val) + { + return val; + } + println!("I said, the minimum is 7, the maximum is 19."); + } +}