From a2347c87fa7af3c54e3639be0fd57bffcc4a824e Mon Sep 17 00:00:00 2001 From: E12345EE12345E <60201680+E12345EE12345E@users.noreply.github.com> Date: Tue, 1 Aug 2023 14:43:59 -0700 Subject: [PATCH 01/10] console display added colors added some colored text to improve the command prompt gameplay viewing experience --- tetris/Cargo.lock | 175 +++++++++++++++++++++++++++++++++++++++++--- tetris/Cargo.toml | 1 + tetris/src/board.rs | 8 +- tetris/src/game.rs | 5 +- tetris/src/main.rs | 8 +- tetris/src/queue.rs | 8 +- 6 files changed, 185 insertions(+), 20 deletions(-) diff --git a/tetris/Cargo.lock b/tetris/Cargo.lock index 98af9a7..e71b89c 100644 --- a/tetris/Cargo.lock +++ b/tetris/Cargo.lock @@ -20,6 +20,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "block-buffer" version = "0.10.3" @@ -41,12 +47,29 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "colored" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +dependencies = [ + "is-terminal", + "lazy_static", + "windows-sys 0.48.0", +] + [[package]] name = "cpufeatures" version = "0.2.5" @@ -82,6 +105,27 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +[[package]] +name = "errno" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "fnv" version = "1.0.7" @@ -171,6 +215,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + [[package]] name = "http" version = "0.2.8" @@ -198,6 +248,17 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.2", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -213,11 +274,23 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" -version = "0.2.132" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "lock_api" @@ -253,7 +326,7 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -271,7 +344,7 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", ] @@ -301,7 +374,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -391,7 +464,20 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "rustix" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", ] [[package]] @@ -497,6 +583,7 @@ dependencies = [ name = "tetris" version = "0.1.0" dependencies = [ + "colored", "futures-util", "itertools", "log", @@ -692,39 +779,105 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/tetris/Cargo.toml b/tetris/Cargo.toml index 7ebe165..a1d4c3c 100644 --- a/tetris/Cargo.toml +++ b/tetris/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" rand = "0.8.5" polynomial = "0.2.4" itertools = "0.10.5" +colored = "2.0.4" tungstenite = "*" serde = { version = "1.0.78", features = ["derive"] } diff --git a/tetris/src/board.rs b/tetris/src/board.rs index 44a4cdd..36ab770 100644 --- a/tetris/src/board.rs +++ b/tetris/src/board.rs @@ -2,9 +2,11 @@ use crate::constants::board_constants::*; use crate::constants::types::*; -use crate::piece::Piece; +use crate::piece::*; +use crate::queue::{piece_type_to_string_colored}; use crate::point_vector::{Point, PointVector}; use std::fmt::{Display, Formatter}; +use colored::*; #[derive(Debug, Clone)] pub struct Board { @@ -357,9 +359,9 @@ impl Board { if self.get(row, col) { out.push_str("■ "); } else if locations.contains(&Point(row as i8, col as i8)) { - out.push_str("⬚ "); + out.push_str(&format!("{} ", piece_type_to_string_colored(active_piece.get_type()))); } else { - out.push_str("□ "); + out.push_str(&format!("{} ", ("▫".truecolor(40,40,40)))); } } out.push_str("\n"); diff --git a/tetris/src/game.rs b/tetris/src/game.rs index bdea441..402ed23 100644 --- a/tetris/src/game.rs +++ b/tetris/src/game.rs @@ -6,11 +6,12 @@ use crate::constants::types::{PieceType, RotationDirection}; use crate::constants::versus_constants::*; use crate::piece::Piece; use crate::point_vector::PointVector; -use crate::queue::{piece_type_to_string, BagType, PieceQueue}; +use crate::queue::{piece_type_to_string, piece_type_to_string_colored, BagType, PieceQueue}; use crate::versus::*; use game_rules_and_data::*; use std::fmt::{Display, Formatter}; use crate::game::game_rules_and_data::SpinBonus::TSpin; +use colored::*; #[derive(Default, Clone)] pub struct Game { @@ -27,7 +28,7 @@ impl Display for Game { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "Queue: {}", self.piece_queue)?; if let Some(hold) = self.hold_piece { - write!(f, "Hold: {}\n", piece_type_to_string(hold))?; + write!(f, "Hold: {}\n", piece_type_to_string_colored(hold))?; } else { write!(f, "Hold: None\n")?; } diff --git a/tetris/src/main.rs b/tetris/src/main.rs index fc3439d..f616155 100644 --- a/tetris/src/main.rs +++ b/tetris/src/main.rs @@ -28,10 +28,11 @@ use crate::piece::Piece; use crate::weight::Weights; use crate::point_vector::Point; use crate::opener::*; +use colored::Colorize; fn main() { - // bot_play(); - tetrio_play(); + bot_play(); + // tetrio_play(); // more_test(); // dt_test(); @@ -63,7 +64,7 @@ fn bot_play() { thread::sleep(time::Duration::from_millis(0)); // println!("{}", bot.get_game()); println!("{}", bot.get_game()); - + println!("{} milliseconds to move", format!("{}", now.elapsed().as_micros() / 1000).green()) } println!( "Making {} moves took {} microseconds on average", @@ -71,6 +72,7 @@ fn bot_play() { time / (bot.get_game().game_data.pieces_placed as u128) ); println!("{}", bot.get_game()); + thread::sleep(time::Duration::from_millis(10000)); } // fn bot_play() { diff --git a/tetris/src/queue.rs b/tetris/src/queue.rs index a5d1c8d..af9f14b 100644 --- a/tetris/src/queue.rs +++ b/tetris/src/queue.rs @@ -8,6 +8,7 @@ use std::collections::VecDeque; use std::fmt::{Display, Formatter}; use std::str::FromStr; use std::string::ParseError; +use colored::*; #[derive(Default, Clone)] pub struct PieceQueue { @@ -129,10 +130,15 @@ pub fn piece_type_to_string(piece: PieceType) -> String { arr[piece].to_owned() } +pub fn piece_type_to_string_colored(piece: PieceType) -> ColoredString { + let arr = ["Z".red(), "L".truecolor(255,128,0), "O".bright_yellow(), "S".green(), "I".bright_blue(), "J".blue(), "T".bright_purple()]; + arr[piece].to_owned() +} + impl Display for PieceQueue { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { for piece in 0..MIN_QUEUE_LENGTH { - write!(f, "{} ", piece_type_to_string(self.queue[piece]))?; + write!(f, "{} ", piece_type_to_string_colored(self.queue[piece]))?; } Ok(()) } From 879631893968f61a5ac1bf20ae4ac75936ec8b8b Mon Sep 17 00:00:00 2001 From: E12345EE12345E <60201680+E12345EE12345E@users.noreply.github.com> Date: Tue, 1 Aug 2023 22:59:18 -0700 Subject: [PATCH 02/10] added burst + local bot dueling burst and bot dueling settings can be found in constants, burst is temporary and only a proof of concept, garbage needs a bar (currently it teleports on screen), bot dueling requires two separate instances of the bot running on the same computer, with the same const LOCALGAMEPLAYFILEPATH, as well as opposite consts BOTNUM and BOTNUM2 --- tetris/Cargo.lock | 68 ++++++++++++++++++++++++++ tetris/Cargo.toml | 1 + tetris/src/board.rs | 18 +++++++ tetris/src/bot.rs | 13 +++-- tetris/src/constants.rs | 9 ++++ tetris/src/game.rs | 10 ++-- tetris/src/localdata.txt | 1 + tetris/src/main.rs | 103 ++++++++++++++++++++++++--------------- tetris/src/players.rs | 13 +++++ 9 files changed, 189 insertions(+), 47 deletions(-) create mode 100644 tetris/src/localdata.txt diff --git a/tetris/Cargo.lock b/tetris/Cargo.lock index e71b89c..513b5e7 100644 --- a/tetris/Cargo.lock +++ b/tetris/Cargo.lock @@ -329,6 +329,73 @@ dependencies = [ "windows-sys 0.36.1", ] +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -587,6 +654,7 @@ dependencies = [ "futures-util", "itertools", "log", + "num", "polynomial", "rand", "serde", diff --git a/tetris/Cargo.toml b/tetris/Cargo.toml index a1d4c3c..7814446 100644 --- a/tetris/Cargo.toml +++ b/tetris/Cargo.toml @@ -9,6 +9,7 @@ rand = "0.8.5" polynomial = "0.2.4" itertools = "0.10.5" colored = "2.0.4" +num = "0.4.1" tungstenite = "*" serde = { version = "1.0.78", features = ["derive"] } diff --git a/tetris/src/board.rs b/tetris/src/board.rs index 36ab770..ce4ad95 100644 --- a/tetris/src/board.rs +++ b/tetris/src/board.rs @@ -103,6 +103,24 @@ impl Board { } } + pub fn add_garbage(&mut self, col: usize, amount: usize) { + let highest = BOARD_HEIGHT; + + for r in 0..highest-amount+1 { + self._set_row(highest-r, self.get_row(highest-r-amount)); + } + + for n in 0..amount { + for w in 0..BOARD_WIDTH { + if w == col { + self.arr[w] &= !(1 << n); + } else { + self.arr[w] |= 1 << n; + } + } + } + } + pub fn remove(&mut self, row: usize, col: usize) { self.arr[col] &= !(1 << row); } diff --git a/tetris/src/bot.rs b/tetris/src/bot.rs index 100b6be..2d4f762 100644 --- a/tetris/src/bot.rs +++ b/tetris/src/bot.rs @@ -78,7 +78,8 @@ impl Player for Bot { // thread::sleep(time::Duration::from_millis(250)); - let (deep_moves, places, deep_scores) = self.move_placement_score(11, &self.weight.clone()); + // println!("{}", self.get_game().board.get_max_height()); + let (deep_moves, places, deep_scores) = self.move_placement_score(MOVEPLACEMENTSCORE - self.get_game().board.get_max_height()*PANICBURST, &self.weight.clone()); let deep_scores: Vec = deep_scores .iter() .map(|(board, versus)| board + versus) @@ -96,9 +97,9 @@ impl Player for Bot { } - println!("{:?}", action); - println!("{}", min_score); - println!("{}", p[0]); + // println!("{:?}", action); + // println!("{}", min_score); + // println!("{}", p[0]); if min_score < -10000.0{ println!("{:?}", p); } @@ -536,4 +537,8 @@ impl Bot { out } + + pub fn addgarbagetest(&mut self, col: usize, amnt: usize) { + self.game.board.add_garbage(col,amnt) + } } diff --git a/tetris/src/constants.rs b/tetris/src/constants.rs index ac15ef6..1b208c7 100644 --- a/tetris/src/constants.rs +++ b/tetris/src/constants.rs @@ -162,6 +162,9 @@ pub mod bot_constants { Game::active_180, // Game::active_drop, ]; + + pub const MOVEPLACEMENTSCORE: usize = 24; + pub const PANICBURST: usize = 1; // test and will likely not be the function used later } pub mod rotation { @@ -432,3 +435,9 @@ pub mod offset { ], ]; } + +pub mod localbotgameplay { + pub const LOCALGAMEPLAYFILEPATH: &str = r".\src\localdata.txt"; + pub const BOTNUM: usize = 0; + pub const BOTNUM2: usize = 1; +} \ No newline at end of file diff --git a/tetris/src/game.rs b/tetris/src/game.rs index 402ed23..a5e514c 100644 --- a/tetris/src/game.rs +++ b/tetris/src/game.rs @@ -286,8 +286,7 @@ impl Game { let lines_cleared = self.board.clear_lines(); let attack_type = attack_type(t_spin_type, lines_cleared); - self.game_data - .update(lines_cleared, attack_type, self.board.all_clear()); + self.game_data.update(lines_cleared, attack_type, self.board.all_clear()); } } @@ -306,7 +305,7 @@ pub mod game_rules_and_data { pub pieces_placed: usize, pub lines_cleared: usize, pub lines_sent: u16, - pub last_sent: u8, + pub last_sent: u16, pub last_cleared: usize, pub t_spin: bool, @@ -334,9 +333,10 @@ pub mod game_rules_and_data { } // update lines sent before adding b2b/combo - let lines_sent = calc_damage(self, attack, lines_cleared); + let mut lines_sent = calc_damage(self, attack, lines_cleared); + if all_clear { lines_sent += 10; } self.lines_sent += lines_sent as u16; - self.last_sent = lines_sent as u8; + self.last_sent = lines_sent as u16; let b2b = BACK_TO_BACK_TYPES.contains(&attack); if b2b { self.b2b += 1; diff --git a/tetris/src/localdata.txt b/tetris/src/localdata.txt new file mode 100644 index 0000000..857f065 --- /dev/null +++ b/tetris/src/localdata.txt @@ -0,0 +1 @@ +00 \ No newline at end of file diff --git a/tetris/src/main.rs b/tetris/src/main.rs index f616155..1015075 100644 --- a/tetris/src/main.rs +++ b/tetris/src/main.rs @@ -23,17 +23,22 @@ use std::collections::VecDeque; use crate::board::Board; use crate::constants::types::Dependencies; use crate::constants::versus_constants::AttackType::T; +use crate::constants::localbotgameplay::*; use crate::game::Game; use crate::piece::Piece; use crate::weight::Weights; use crate::point_vector::Point; use crate::opener::*; use colored::Colorize; +use std::fs; +use std::string::*; fn main() { - bot_play(); + // bot_play(); + bot_play_local(); // tetrio_play(); + // test_cheese(); // more_test(); // dt_test(); } @@ -75,43 +80,65 @@ fn bot_play() { thread::sleep(time::Duration::from_millis(10000)); } -// fn bot_play() { -// let mut bot = Bot::default(); -// let mut game = bot.get_game_mut(); -// game.set_active_piece(Piece::new(6)); -// println!("{}", game); -// game.board.add(0,0); -// game.board.add(1, 0); -// game.board.add(2, 0); -// game.board.add(0, 1); -// game.board.add(0, 3); -// game.board.add(2, 3); -// game.board.add(0, 4); -// game.board.add(1, 4); -// game.board.add(2, 4); -// game.board.add(0, 5); -// game.board.add(1, 5); -// game.board.add(2, 5); -// game.board.add(0, 6); -// game.board.add(1, 6); -// game.board.add(2, 6); -// game.board.add(0, 7); -// game.board.add(1, 7); -// game.board.add(2, 7); -// game.board.add(0, 8); -// game.board.add(1, 8); -// game.board.add(2, 8); -// game.board.add(0, 9); -// game.board.add(1, 9); -// game.board.add(2, 9); -// println!("{}", game); -// let placements = Bot::move_placement_score_1d(game, &Default::default()).1; -// for placement in placements{ -// game.board.add_list(placement.abs_locations().unwrap()); -// println!("{}", game); -// game.board.remove_list(placement.abs_locations().unwrap()); -// } -// } +fn bot_play_local() { + let mut bot = Bot::default(); + println!("{}", bot.get_game().board.get_arr().len()); + + let mut time = 0; + while !bot.get_game().get_game_over() && bot.get_game().game_data.pieces_placed < 10000 { + + let now = time::Instant::now(); + bot.make_move(); + time += now.elapsed().as_micros(); + + let mut commsfile = fs::read_to_string(LOCALGAMEPLAYFILEPATH).expect("e"); + let garbage = commsfile.chars().nth(BOTNUM).expect("e").to_string().parse::().unwrap(); + bot.addgarbagetest((time % 10).try_into().unwrap(), garbage); + commsfile.replace_range(BOTNUM..BOTNUM+1, "0"); + let _ = fs::write(LOCALGAMEPLAYFILEPATH, commsfile); + + thread::sleep(time::Duration::from_millis(0)); + // println!("{}", bot.get_game()); + println!("{}", bot.get_game()); + println!("{} milliseconds to move", format!("{}", now.elapsed().as_micros() / 1000).green()) + } + println!( + "Making {} moves took {} microseconds on average", + bot.get_game().game_data.pieces_placed, + time / (bot.get_game().game_data.pieces_placed as u128) + ); + println!("{}", bot.get_game()); + thread::sleep(time::Duration::from_millis(100000)); +} + +fn test_cheese() { + let mut bot = Bot::default(); + println!("{}", bot.get_game().board.get_arr().len()); + + println!("{}", bot.get_game()); + + let mut time = 0; + while !bot.get_game().get_game_over() && bot.get_game().game_data.pieces_placed < 10000 { + + let now = time::Instant::now(); + bot.make_move(); + time += now.elapsed().as_micros(); + if bot.get_game().game_data.pieces_placed % 3 == 0 { bot.addgarbagetest((time % 10).try_into().unwrap(), 1); } // cheese timer in zen mode be like + + thread::sleep(time::Duration::from_millis(0)); + // println!("{}", bot.get_game()); + println!("{}", bot.get_game()); + println!("{} milliseconds to move", format!("{}", now.elapsed().as_micros() / 1000).green()); + println!("{} pieces placed", format!("{}", bot.get_game().game_data.pieces_placed).green()) + } + println!( + "Making {} moves took {} microseconds on average", + bot.get_game().game_data.pieces_placed, + time / (bot.get_game().game_data.pieces_placed as u128) + ); + println!("{}", bot.get_game()); + thread::sleep(time::Duration::from_millis(10000)); +} fn dt_test() { let mut bot = Bot::default(); diff --git a/tetris/src/players.rs b/tetris/src/players.rs index 1752d54..c124c1d 100644 --- a/tetris/src/players.rs +++ b/tetris/src/players.rs @@ -4,6 +4,10 @@ use crate::communications::Suggestion; use crate::constants::bot_constants::*; use crate::constants::types::*; use crate::game::Game; +use num::clamp; +use std::fs; +use std::string::*; +use crate::constants::localbotgameplay::*; pub trait Player { fn get_game(&self) -> &Game; @@ -17,6 +21,15 @@ pub trait Player { let action = self.get_next_move(); // println!("{:?}", action); do_move_list(self.get_game_mut(), action); + + // for local gameplay in cmd + let mut commsfile = fs::read_to_string(LOCALGAMEPLAYFILEPATH).expect("e"); + let clamped_lines_sent = clamp(self.get_game().game_data.last_sent + commsfile.chars().nth(BOTNUM2).expect("e").to_string().parse::().unwrap(), 0, 9); + commsfile.replace_range(BOTNUM2..BOTNUM2+1, &clamped_lines_sent.to_string()); + let _ = fs::write(LOCALGAMEPLAYFILEPATH, commsfile); + + // println!("{}", clamped_lines_sent) + // println!("{}", self.get_game().game_data.last_sent); true } From c6ca5bc19c520ca1157e0ca8c338e6c22697e05c Mon Sep 17 00:00:00 2001 From: E12345EE12345E <60201680+E12345EE12345E@users.noreply.github.com> Date: Wed, 2 Aug 2023 22:12:36 -0700 Subject: [PATCH 03/10] bot weights overhaul massively boosted efficiency and survivability from the bot (queue fix implemented as well) --- tetris/src/board.rs | 3 ++- tetris/src/bot.rs | 8 ++++---- tetris/src/communications.rs | 5 ----- tetris/src/constants.rs | 2 ++ tetris/src/game.rs | 20 +++++++++++++------- tetris/src/main.rs | 19 +++++++++++-------- tetris/src/players.rs | 16 ++++++++++++---- tetris/src/queue.rs | 8 ++------ tetris/src/weight.rs | 16 ++++++++-------- 9 files changed, 54 insertions(+), 43 deletions(-) diff --git a/tetris/src/board.rs b/tetris/src/board.rs index ce4ad95..6e32c0f 100644 --- a/tetris/src/board.rs +++ b/tetris/src/board.rs @@ -7,6 +7,7 @@ use crate::queue::{piece_type_to_string_colored}; use crate::point_vector::{Point, PointVector}; use std::fmt::{Display, Formatter}; use colored::*; +use num::clamp; #[derive(Debug, Clone)] pub struct Board { @@ -379,7 +380,7 @@ impl Board { } else if locations.contains(&Point(row as i8, col as i8)) { out.push_str(&format!("{} ", piece_type_to_string_colored(active_piece.get_type()))); } else { - out.push_str(&format!("{} ", ("▫".truecolor(40,40,40)))); + out.push_str(&format!("{} ", ("▫".truecolor(clamp(8*row,0,255).try_into().unwrap(),clamp(100-4*row,0,255).try_into().unwrap(),clamp(40,0,255).try_into().unwrap())))); } } out.push_str("\n"); diff --git a/tetris/src/bot.rs b/tetris/src/bot.rs index 2d4f762..63bb534 100644 --- a/tetris/src/bot.rs +++ b/tetris/src/bot.rs @@ -183,7 +183,7 @@ impl Bot { let mut next_scores = ScoreList::new(); //pruning parameters - let n = 50; + let n = 100; let prune_depth = 1; for curr_depth in 1..depth { @@ -232,7 +232,7 @@ impl Bot { next_moves.push(one_move.clone()); next_placements.push(placements.clone()); - next_scores.push((board, (versus + add_versus) * (1.0-(0.5*curr_depth as f32/depth as f32)))); + next_scores.push((board, (versus + add_versus) * (1.0-(0.25*curr_depth as f32/depth as f32)))); } } curr_moves = mem::take(&mut next_moves); @@ -494,7 +494,7 @@ impl Bot { let mut extra = 0.0; if pc { - extra -= 1000000.0; + extra -= 100.0; } if t_spin { extra -= 100.0 @@ -538,7 +538,7 @@ impl Bot { out } - pub fn addgarbagetest(&mut self, col: usize, amnt: usize) { + pub fn addgarbage(&mut self, col: usize, amnt: usize) { self.game.board.add_garbage(col,amnt) } } diff --git a/tetris/src/communications.rs b/tetris/src/communications.rs index d5933e4..2251ab1 100644 --- a/tetris/src/communications.rs +++ b/tetris/src/communications.rs @@ -112,11 +112,6 @@ async fn handle_connection(peer: SocketAddr, stream: TcpStream) -> Result<()> { }, "stop" => eprintln!("stop game"), "start" => { - let mut i_hate_osk: usize = 21; // 0+1+2+3+4+5+6 = 21 - for i in 0..6 { - i_hate_osk -= bot.get_game().piece_queue.peek_index(i) - } - bot.get_game_mut().set_active_piece(Piece::new(i_hate_osk)); ws_sender.send(Message::Text(serde_json::to_string(&json!(bot.make_suggest_move())).unwrap())).await? }, other => eprintln!("unexpected packet of type {}", other), diff --git a/tetris/src/constants.rs b/tetris/src/constants.rs index 1b208c7..562e772 100644 --- a/tetris/src/constants.rs +++ b/tetris/src/constants.rs @@ -98,6 +98,7 @@ pub mod queue_constants { pub const MULTIPLIER: usize = 16807; pub const MODULUS: usize = 2147483647; + pub const CONSOLE_DISPLAY_QUEUE: bool = true; } pub mod bot_constants { @@ -437,6 +438,7 @@ pub mod offset { } pub mod localbotgameplay { + pub const ALLOWLOCALGAMEPLAY: bool = true; pub const LOCALGAMEPLAYFILEPATH: &str = r".\src\localdata.txt"; pub const BOTNUM: usize = 0; pub const BOTNUM2: usize = 1; diff --git a/tetris/src/game.rs b/tetris/src/game.rs index a5e514c..bbcc740 100644 --- a/tetris/src/game.rs +++ b/tetris/src/game.rs @@ -4,6 +4,7 @@ use crate::board::Board; use crate::constants::piece_constants::{NUM_ROTATE_STATES, RELATIVE_CORNERS}; use crate::constants::types::{PieceType, RotationDirection}; use crate::constants::versus_constants::*; +use crate::constants::queue_constants::*; use crate::piece::Piece; use crate::point_vector::PointVector; use crate::queue::{piece_type_to_string, piece_type_to_string_colored, BagType, PieceQueue}; @@ -26,11 +27,13 @@ pub struct Game { impl Display for Game { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "Queue: {}", self.piece_queue)?; - if let Some(hold) = self.hold_piece { - write!(f, "Hold: {}\n", piece_type_to_string_colored(hold))?; - } else { - write!(f, "Hold: None\n")?; + if CONSOLE_DISPLAY_QUEUE { + write!(f, "Queue: {}", self.piece_queue)?; + if let Some(hold) = self.hold_piece { + write!(f, "Hold: {}\n", piece_type_to_string_colored(hold))?; + } else { + write!(f, "Hold: None\n")?; + } } write!(f, "{}", self.board.display_with_active(&self.active_piece))?; @@ -52,11 +55,14 @@ impl Game { } pub fn from_rules(seed: Option, game_rules: GameRules) -> Self { - Self { + let mut out = Self { piece_queue: PieceQueue::new(seed), game_rules, ..Default::default() - } + }; + + out.active_piece = out.piece_queue.next(); + out } // piece getters and setters pub fn get_active_piece(&self) -> &Piece { diff --git a/tetris/src/main.rs b/tetris/src/main.rs index 1015075..9035bc3 100644 --- a/tetris/src/main.rs +++ b/tetris/src/main.rs @@ -86,21 +86,24 @@ fn bot_play_local() { let mut time = 0; while !bot.get_game().get_game_over() && bot.get_game().game_data.pieces_placed < 10000 { - let now = time::Instant::now(); bot.make_move(); time += now.elapsed().as_micros(); - let mut commsfile = fs::read_to_string(LOCALGAMEPLAYFILEPATH).expect("e"); - let garbage = commsfile.chars().nth(BOTNUM).expect("e").to_string().parse::().unwrap(); - bot.addgarbagetest((time % 10).try_into().unwrap(), garbage); - commsfile.replace_range(BOTNUM..BOTNUM+1, "0"); - let _ = fs::write(LOCALGAMEPLAYFILEPATH, commsfile); + if ALLOWLOCALGAMEPLAY && bot.get_game().game_data.combo == 0 { + let mut commsfile = fs::read_to_string(LOCALGAMEPLAYFILEPATH).expect("e"); + let garbage = commsfile.chars().nth(BOTNUM).expect("e").to_string().parse::().unwrap(); + bot.addgarbage((time % 10).try_into().unwrap(), garbage); + commsfile.replace_range(BOTNUM..BOTNUM+1, "0"); + let _ = fs::write(LOCALGAMEPLAYFILEPATH, commsfile); + } thread::sleep(time::Duration::from_millis(0)); // println!("{}", bot.get_game()); println!("{}", bot.get_game()); - println!("{} milliseconds to move", format!("{}", now.elapsed().as_micros() / 1000).green()) + println!("{} milliseconds to move", format!("{}", now.elapsed().as_micros() / 1000).green()); + println!("{} lines sent / {} pieces placed = {} app", format!("{}", bot.get_game().game_data.lines_sent).green(), format!("{}", bot.get_game().game_data.pieces_placed).green(), format!("{}", (bot.get_game().game_data.lines_sent as f64) / (bot.get_game().game_data.pieces_placed as f64)).green()); + println!("{} b2b, {} combo", format!("{}", bot.get_game().game_data.b2b).green(), format!("{}", bot.get_game().game_data.combo).green()) } println!( "Making {} moves took {} microseconds on average", @@ -123,7 +126,7 @@ fn test_cheese() { let now = time::Instant::now(); bot.make_move(); time += now.elapsed().as_micros(); - if bot.get_game().game_data.pieces_placed % 3 == 0 { bot.addgarbagetest((time % 10).try_into().unwrap(), 1); } // cheese timer in zen mode be like + if bot.get_game().game_data.pieces_placed % 3 == 0 { bot.addgarbage((time % 10).try_into().unwrap(), 1); } // cheese timer in zen mode be like thread::sleep(time::Duration::from_millis(0)); // println!("{}", bot.get_game()); diff --git a/tetris/src/players.rs b/tetris/src/players.rs index c124c1d..991e288 100644 --- a/tetris/src/players.rs +++ b/tetris/src/players.rs @@ -23,10 +23,18 @@ pub trait Player { do_move_list(self.get_game_mut(), action); // for local gameplay in cmd - let mut commsfile = fs::read_to_string(LOCALGAMEPLAYFILEPATH).expect("e"); - let clamped_lines_sent = clamp(self.get_game().game_data.last_sent + commsfile.chars().nth(BOTNUM2).expect("e").to_string().parse::().unwrap(), 0, 9); - commsfile.replace_range(BOTNUM2..BOTNUM2+1, &clamped_lines_sent.to_string()); - let _ = fs::write(LOCALGAMEPLAYFILEPATH, commsfile); + if ALLOWLOCALGAMEPLAY { + let mut commsfile = fs::read_to_string(LOCALGAMEPLAYFILEPATH).expect("e"); + let mut garbage = commsfile.chars().nth(BOTNUM).expect("e").to_string().parse::().unwrap(); + let clamped_lines_sent = clamp(clamp(self.get_game().game_data.last_sent as i16 - garbage, 0, 9) + commsfile.chars().nth(BOTNUM2).expect("e").to_string().parse::().unwrap(), 0, 9); + garbage = clamp(garbage - self.get_game().game_data.last_sent as i16, 0, 9); + commsfile.replace_range(BOTNUM..BOTNUM+1, &garbage.to_string()); + commsfile.replace_range(BOTNUM2..BOTNUM2+1, &clamped_lines_sent.to_string()); + let _ = fs::write(LOCALGAMEPLAYFILEPATH, commsfile); + + println!("{}", &garbage.to_string()); + println!("{}", &clamped_lines_sent.to_string()); + } // println!("{}", clamped_lines_sent) // println!("{}", self.get_game().game_data.last_sent); diff --git a/tetris/src/queue.rs b/tetris/src/queue.rs index af9f14b..394cc6b 100644 --- a/tetris/src/queue.rs +++ b/tetris/src/queue.rs @@ -19,14 +19,10 @@ pub struct PieceQueue { impl PieceQueue { pub fn new(optional_seed: Option) -> Self { - let mut out = Self { + Self { seed: optional_seed.unwrap_or_else(|| rand::thread_rng().gen_range(0..MODULUS - 1)), ..Default::default() - }; - - out.next_bag(); - out.next(); - out + } } pub fn new_alt_randomizer(optional_seed: Option, randomizer: BagType) -> Self { diff --git a/tetris/src/weight.rs b/tetris/src/weight.rs index 4e817da..c2771dc 100644 --- a/tetris/src/weight.rs +++ b/tetris/src/weight.rs @@ -20,18 +20,18 @@ pub struct Weights { impl Default for Weights { fn default() -> Self { Self { - height_weight: Polynomial::new(vec![0.0, -10.0, 5.0]), + height_weight: Polynomial::new(vec![0.0, -20.0, 0.2, 0.4]), adjacent_height_differences_weight: Polynomial::new(vec![0.0, 3.0, 2.0]), total_height_difference_weight: Polynomial::new(vec![0.0, 0.0, 0.0]), num_hole_total_weight: Polynomial::new(vec![0.0, 30.0, 5.0]), num_hole_weighted_weight: Polynomial::new(vec![0.0, 10.0, 3.0]), - cell_covered_weight: Polynomial::new(vec![0.0, 5.0, 0.0]), + cell_covered_weight: Polynomial::new(vec![0.0, 5.0]), - t_slot_weight: Polynomial::new(vec![0.0, -150.0, 50.0]), - b2b_weight: Polynomial::new(vec![0.0, -15.0]), - combo_weight: Polynomial::new(vec![0.0, 8.0, -4.0]), - damage_weight: Polynomial::new(vec![0.0, 28.0, -8.0]), - clear_weight: Polynomial::new(vec![0.0, 49.0, -7.0]), + t_slot_weight: Polynomial::new(vec![0.0, -500.0, 150.0]), + b2b_weight: Polynomial::new(vec![0.0, -40.0, 2.0]), + combo_weight: Polynomial::new(vec![0.0, 20.0, -8.0, -0.5]), + damage_weight: Polynomial::new(vec![0.0, 25.0, -8.0, -1.5]), + clear_weight: Polynomial::new(vec![0.0, -20.0]), } } -} +} \ No newline at end of file From e5b248b2cea03ca2e97e7f9d6197e0d98fac92fa Mon Sep 17 00:00:00 2001 From: Sashimi Date: Thu, 3 Aug 2023 02:27:56 -0700 Subject: [PATCH 04/10] change "zzztoj playstyle" implementation --- tetris/src/bot.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tetris/src/bot.rs b/tetris/src/bot.rs index 63bb534..9f25f7f 100644 --- a/tetris/src/bot.rs +++ b/tetris/src/bot.rs @@ -79,7 +79,7 @@ impl Player for Bot { // thread::sleep(time::Duration::from_millis(250)); // println!("{}", self.get_game().board.get_max_height()); - let (deep_moves, places, deep_scores) = self.move_placement_score(MOVEPLACEMENTSCORE - self.get_game().board.get_max_height()*PANICBURST, &self.weight.clone()); + let (deep_moves, places, deep_scores) = self.move_placement_score(11, &self.weight.clone()); let deep_scores: Vec = deep_scores .iter() .map(|(board, versus)| board + versus) @@ -183,7 +183,7 @@ impl Bot { let mut next_scores = ScoreList::new(); //pruning parameters - let n = 100; + let n = 100000 / (400 + 40*self.get_game().board.get_max_height()); let prune_depth = 1; for curr_depth in 1..depth { From 1cde70ce3dbefa3375bc5969a6bf6258e3605c3e Mon Sep 17 00:00:00 2001 From: E12345EE12345E <60201680+E12345EE12345E@users.noreply.github.com> Date: Fri, 4 Aug 2023 12:29:32 -0700 Subject: [PATCH 05/10] tspin vision and better stacking ehehehhe it can now tspin very well --- tetris/src/board.rs | 140 +++++++++++++++++++++++++++++++++++++++- tetris/src/bot.rs | 43 ++++++++---- tetris/src/constants.rs | 8 +-- tetris/src/game.rs | 19 +++++- tetris/src/main.rs | 44 +++++++++++++ tetris/src/players.rs | 4 +- tetris/src/queue.rs | 9 +++ tetris/src/weight.rs | 20 ++++-- 8 files changed, 261 insertions(+), 26 deletions(-) diff --git a/tetris/src/board.rs b/tetris/src/board.rs index 6e32c0f..641b9d4 100644 --- a/tetris/src/board.rs +++ b/tetris/src/board.rs @@ -8,6 +8,7 @@ use crate::point_vector::{Point, PointVector}; use std::fmt::{Display, Formatter}; use colored::*; use num::clamp; +use crate::weight::Weights; #[derive(Debug, Clone)] pub struct Board { @@ -297,6 +298,67 @@ impl Board { (holes_count_total, holes_count_weighted, cell_covered_count) } + pub fn horizontal_holes_weighted(&self, weight: &Weights) -> f32 { + let mut holes_count_total = 0; + let mut holes_count_weighted = 0; + let mut finalweight = 0.0; + + for row in 0..self.get_max_height() { + // only counting when you find a filled block + let mut counting = true; + + for col in 0..BOARD_WIDTH { + let spot = self.get(row, col); + // hole + if !spot { + holes_count_total += 1; + if counting { + holes_count_weighted += 1; + counting = false; + } + } else { + counting = true; + } + } + finalweight += (holes_count_total as f32)*0.0 + weight.holes_per_row_weighted_weight.eval(holes_count_weighted as f32); + holes_count_total = 0; + holes_count_weighted = 0; + } + + finalweight + } + + pub fn count_horizontal_holes(&self) -> f32 { + let mut holes_count_total = 0; + let mut holes_count_weighted = 0; + let mut finalcount = 0.0; + + for row in 0..self.get_max_height() { + // only counting when you find a filled block + let mut counting = true; + + for col in 0..BOARD_WIDTH { + let spot = self.get(row, col); + // hole + if !spot { + holes_count_total += 1; + if counting { + holes_count_weighted += 1; + counting = false; + } + } else { + counting = true; + } + } + finalcount += holes_count_weighted as f32; + println!("row {} has {} weighted holes", row, holes_count_weighted); + holes_count_total = 0; + holes_count_weighted = 0; + } + + finalcount + } + fn check_hor_t(arr: Vec) -> bool { // only for horizontal t slots rn @@ -308,9 +370,46 @@ impl Board { // 0 0 0 // 1 0 1 - arr == [0b101, 0b000, 0b001] || arr == [0b001, 0b000, 0b101] - // arr == vec![5, 0, 1] || arr == vec![1, 0, 5] + // 1 0 1 + // 0 0 0 + // 1 0 1 + + arr == [0b101, 0b000, 0b001] || arr == [0b001, 0b000, 0b101] || arr == [0b101, 0b000, 0b101] + } + fn check_special_t(arr: Vec) -> bool { + // special tspins + + // 1 1 0 0 1 + // 1 0 0 0 1 + // 1 0 1 1 1 + // 1 0 0 1 1 + // 1 0 1 1 1 + + arr == [0b11111, 0b10000, 0b00101, 0b00111, 0b11111] || arr == [0b11111, 0b00111, 0b00101, 0b10000, 0b11111] || + + // 1 1 0 0 0 + // 1 0 0 0 0 + // 1 0 1 1 1 + // 1 0 0 1 1 + // 1 0 1 1 1 + + arr == [0b11111, 0b10000, 0b00101, 0b00111, 0b00111] || arr == [0b00111, 0b00111, 0b00101, 0b10000, 0b11111] || + + // 1 1 0 0 1 + // 1 0 0 0 1 + // 1 0 1 1 1 + // 1 0 0 1 1 + // 1 0 0 1 1 + arr == [0b11111, 0b10000, 0b00100, 0b00111, 0b11111] || arr == [0b11111, 0b00111, 0b00100, 0b10000, 0b11111] || + + // 1 1 0 0 0 + // 1 0 0 0 0 + // 1 0 1 1 1 + // 1 0 0 1 1 + // 1 0 0 1 1 + + arr == [0b11111, 0b10000, 0b00100, 0b00111, 0b00111] || arr == [0b00111, 0b00111, 0b00100, 0b10000, 0b11111] } pub fn t_slot(&self) -> usize { let h = self.get_max_height(); @@ -331,8 +430,45 @@ impl Board { out += Board::check_hor_t(columns) as usize; } } + + if h - l < 5 { + return out + } + + for row in l..(h-5) { + let mask = 0b11111 << row; + for columns in self.arr.windows(5) { + // create a 5x5 grid + let columns: Vec = columns.iter().map(|x| x & mask).collect(); + + // checks if it is a t slot + out += Board::check_special_t(columns) as usize; + } + } + out + } + pub fn special_t_slot(&self) -> usize { + let h = self.get_max_height(); + let l = self.get_min_height(); + + if h - l < 5 { + return 0 + } + + let mut out = 0; + for row in l..(h-5) { + let mask = 0b11111 << row; + for columns in self.arr.windows(5) { + // create a 5x5 grid + let columns: Vec = columns.iter().map(|x| x & mask).collect(); + // checks if it is a t slot + out += Board::check_special_t(columns) as usize; + } + } + + out } pub fn get_max_height_difference(&self) -> usize { diff --git a/tetris/src/bot.rs b/tetris/src/bot.rs index 63bb534..837d2e8 100644 --- a/tetris/src/bot.rs +++ b/tetris/src/bot.rs @@ -18,7 +18,10 @@ use crate::communications::Suggestion; use crate::{Dependency, Opener, OpenerStatus, Point}; use crate::book::openers; use crate::constants::board_constants::BOARD_WIDTH; +use crate::constants::queue_constants::MIN_QUEUE_LENGTH; use crate::point_vector::PointVector; +use num::clamp; +use num::traits::Pow; pub struct Bot { @@ -183,7 +186,7 @@ impl Bot { let mut next_scores = ScoreList::new(); //pruning parameters - let n = 100; + let n = 400; let prune_depth = 1; for curr_depth in 1..depth { @@ -201,7 +204,7 @@ impl Bot { .unzip(); curr_scores.sort_by(|(v1, b1), (v2, b2)| (v1 + b1).partial_cmp(&(v2 + b2)).unwrap()); - curr_scores.truncate(n); + curr_scores.truncate(1 + n - n * curr_depth / depth); } //generating next_mps @@ -432,7 +435,7 @@ impl Bot { // PC (pseudo) PRUNING if false && (game.board.get_mino_count() % 2 == 0) { // pseudo pruning, gives a large penalty for unsolvable/hard to solve boards - let penalty = (100000.0, Bot::score_board(&game.board, weights)); + let penalty = (100.0, Bot::score_board(&game, &game.board, weights)); let target_height = 4 + (game.board.get_mino_count() % 4)/2; @@ -470,16 +473,16 @@ impl Bot { } return ( - Bot::score_board(&game.board, weights), + Bot::score_board(&game, &game.board, weights), Bot::score_versus(&game.game_data, weights), ) } - fn score_board(board: &Board, weights: &Weights) -> Score { + fn score_board(game: &Game, board: &Board, weights: &Weights) -> Score { Bot::get_holes_and_cell_covered_score(board, weights) + Bot::get_height_score(board, weights) + Bot::get_height_differences_score(board, weights) - + Bot::get_t_slot_score(board, weights) + + Bot::get_t_slot_score(game, board, weights) } fn score_versus(game_data: &GameData, weight: &Weights) -> Score { @@ -494,12 +497,20 @@ impl Bot { let mut extra = 0.0; if pc { - extra -= 100.0; + extra -= 10000.0; } if t_spin { - extra -= 100.0 + extra -= weight.tspin_reward*weight.tspin_reward_expo.pow(game_data.last_cleared as f32); } - + if game_data.last_placed_piece.get_type() == 6 { + match game_data.t_spin_type { + 0 => extra += weight.waste_t_weight, + 1 => extra += weight.waste_t_weight * clamp(2 - game_data.last_cleared, 0, 1) as f32, // doubles and triples should not be punished + 2 => extra += weight.waste_t_weight * 0.8 * clamp(2 - game_data.last_cleared, 0, 1) as f32, // minis should be punished less but not by much + _ => extra += weight.waste_t_weight, // idk + } + } + combo_score + b2b + attack + clear + extra } @@ -517,8 +528,9 @@ impl Bot { adjacent_score + total_score } - pub(crate) fn get_t_slot_score(board: &Board, weight: &Weights) -> f32 { - weight.t_slot_weight.eval(board.t_slot() as f32) + pub(crate) fn get_t_slot_score(game: &Game, board: &Board, weight: &Weights) -> f32 { + weight.t_slot_weight.eval(board.t_slot() as f32) * (1.0 - (game.nearest_tpiece() as f32 / MIN_QUEUE_LENGTH as f32)) + // + weight.t_slot_special_weight.eval(board.special_t_slot() as f32) } fn get_height_score(board: &Board, weight: &Weights) -> f32 { @@ -534,6 +546,7 @@ impl Bot { out += weight.num_hole_total_weight.eval(holes_t as f32); out += weight.num_hole_weighted_weight.eval(holes_w as f32); out += weight.cell_covered_weight.eval(covered as f32); + out += board.horizontal_holes_weighted(weight); out } @@ -541,4 +554,12 @@ impl Bot { pub fn addgarbage(&mut self, col: usize, amnt: usize) { self.game.board.add_garbage(col,amnt) } + + pub fn addtoboard(&mut self, row: usize, col: usize) { + self.game.board.add(row, col) + } + + pub fn removefromboard(&mut self, row: usize, col: usize) { + self.game.board.remove(row, col) + } } diff --git a/tetris/src/constants.rs b/tetris/src/constants.rs index 562e772..92ae2fc 100644 --- a/tetris/src/constants.rs +++ b/tetris/src/constants.rs @@ -83,7 +83,7 @@ pub mod versus_constants { TT, } - #[derive(Debug, PartialEq)] + #[derive(Copy, Clone, Debug, PartialEq)] pub enum TSpinType { None, Full, @@ -92,7 +92,7 @@ pub mod versus_constants { } pub mod queue_constants { - pub const MIN_QUEUE_LENGTH: usize = 6; + pub const MIN_QUEUE_LENGTH: usize = 10; // lehmer RNG (MINSTD) pub const MULTIPLIER: usize = 16807; @@ -164,8 +164,8 @@ pub mod bot_constants { // Game::active_drop, ]; - pub const MOVEPLACEMENTSCORE: usize = 24; - pub const PANICBURST: usize = 1; // test and will likely not be the function used later + pub const MOVEPLACEMENTSCORE: usize = 14; + pub const PANICBURST: usize = 0; // test and will likely not be the function used later } pub mod rotation { diff --git a/tetris/src/game.rs b/tetris/src/game.rs index bbcc740..96fbd9c 100644 --- a/tetris/src/game.rs +++ b/tetris/src/game.rs @@ -119,6 +119,7 @@ impl Game { pub fn active_drop(&mut self) -> bool { let out = self.active_down(); + if out { self.active_piece.set_kick(999)} while out && self.active_down() {} out } @@ -282,17 +283,25 @@ impl Game { self.board.set_piece(&self.active_piece); self.update(); + self.game_data.last_placed_piece = self.active_piece; self.active_piece = self.piece_queue.next(); true } + pub fn nearest_tpiece(&self) -> usize { + if self.hold_piece == Some(6) || self.active_piece.get_type() == 6 { + return 0; + } + self.piece_queue.nearest_tpiece() + } + pub fn update(&mut self) { let t_spin_type = Game::get_t_spin_type(&self.active_piece, &self.board); let lines_cleared = self.board.clear_lines(); let attack_type = attack_type(t_spin_type, lines_cleared); - self.game_data.update(lines_cleared, attack_type, self.board.all_clear()); + self.game_data.update(lines_cleared, attack_type, t_spin_type, self.board.all_clear()); } } @@ -313,28 +322,32 @@ pub mod game_rules_and_data { pub lines_sent: u16, pub last_sent: u16, pub last_cleared: usize, + pub last_placed_piece: Piece, pub t_spin: bool, + pub t_spin_type: u16, pub game_over: bool, } impl GameData { - pub fn update(&mut self, lines_cleared: usize, attack: AttackType, all_clear: bool) { + pub fn update(&mut self, lines_cleared: usize, attack: AttackType, t_spin_type: TSpinType, all_clear: bool) { self.pieces_placed += 1; + self.t_spin_type = t_spin_type as u16; if lines_cleared == 0 { self.combo = 0; self.all_clear = false; self.last_cleared = 0; self.last_sent = 0; + self.t_spin = false; return; } self.lines_cleared += lines_cleared; self.last_cleared = lines_cleared; - if attack == TD{ + if self.t_spin_type > 0 { self.t_spin = true; } diff --git a/tetris/src/main.rs b/tetris/src/main.rs index 9035bc3..b2ebd7f 100644 --- a/tetris/src/main.rs +++ b/tetris/src/main.rs @@ -38,6 +38,7 @@ fn main() { bot_play_local(); // tetrio_play(); + // test_tspinkicks(); // test_cheese(); // more_test(); // dt_test(); @@ -114,6 +115,49 @@ fn bot_play_local() { thread::sleep(time::Duration::from_millis(100000)); } +fn test_tspinkicks() { + let mut bot = Bot::default(); + println!("{}", bot.get_game().board.get_arr().len()); + + bot.addgarbage(3,3); + bot.removefromboard(1,2); + //bot.removefromboard(0,2); + bot.addtoboard(3,4); + bot.addtoboard(4,4); + bot.addtoboard(4,3); + + println!("{}", bot.get_game()); + + let mut time = 0; + while !bot.get_game().get_game_over() && bot.get_game().game_data.pieces_placed < 10000 { + let now = time::Instant::now(); + bot.make_move(); + time += now.elapsed().as_micros(); + + if ALLOWLOCALGAMEPLAY && bot.get_game().game_data.combo == 0 { + let mut commsfile = fs::read_to_string(LOCALGAMEPLAYFILEPATH).expect("e"); + let garbage = commsfile.chars().nth(BOTNUM).expect("e").to_string().parse::().unwrap(); + bot.addgarbage((time % 10).try_into().unwrap(), garbage); + commsfile.replace_range(BOTNUM..BOTNUM+1, "0"); + let _ = fs::write(LOCALGAMEPLAYFILEPATH, commsfile); + } + + thread::sleep(time::Duration::from_millis(0)); + // println!("{}", bot.get_game()); + println!("{}", bot.get_game()); + println!("{} milliseconds to move", format!("{}", now.elapsed().as_micros() / 1000).green()); + println!("{} lines sent / {} pieces placed = {} app", format!("{}", bot.get_game().game_data.lines_sent).green(), format!("{}", bot.get_game().game_data.pieces_placed).green(), format!("{}", (bot.get_game().game_data.lines_sent as f64) / (bot.get_game().game_data.pieces_placed as f64)).green()); + println!("{} b2b, {} combo", format!("{}", bot.get_game().game_data.b2b).green(), format!("{}", bot.get_game().game_data.combo).green()) + } + println!( + "Making {} moves took {} microseconds on average", + bot.get_game().game_data.pieces_placed, + time / (bot.get_game().game_data.pieces_placed as u128) + ); + println!("{}", bot.get_game()); + thread::sleep(time::Duration::from_millis(100000)); +} + fn test_cheese() { let mut bot = Bot::default(); println!("{}", bot.get_game().board.get_arr().len()); diff --git a/tetris/src/players.rs b/tetris/src/players.rs index 991e288..c45259b 100644 --- a/tetris/src/players.rs +++ b/tetris/src/players.rs @@ -32,8 +32,8 @@ pub trait Player { commsfile.replace_range(BOTNUM2..BOTNUM2+1, &clamped_lines_sent.to_string()); let _ = fs::write(LOCALGAMEPLAYFILEPATH, commsfile); - println!("{}", &garbage.to_string()); - println!("{}", &clamped_lines_sent.to_string()); + // println!("{}", &garbage.to_string()); + // println!("{}", &clamped_lines_sent.to_string()); } // println!("{}", clamped_lines_sent) diff --git a/tetris/src/queue.rs b/tetris/src/queue.rs index 394cc6b..2bc12b3 100644 --- a/tetris/src/queue.rs +++ b/tetris/src/queue.rs @@ -119,6 +119,15 @@ impl PieceQueue { } arr } + + pub fn nearest_tpiece(&self) -> usize { + for piece in 0..MIN_QUEUE_LENGTH { + if self.queue[piece] == 6 { + return piece; + } + } + return MIN_QUEUE_LENGTH; + } } pub fn piece_type_to_string(piece: PieceType) -> String { diff --git a/tetris/src/weight.rs b/tetris/src/weight.rs index c2771dc..13c61b8 100644 --- a/tetris/src/weight.rs +++ b/tetris/src/weight.rs @@ -8,13 +8,19 @@ pub struct Weights { pub total_height_difference_weight: Polynomial, pub num_hole_total_weight: Polynomial, pub num_hole_weighted_weight: Polynomial, + pub holes_per_row_weighted_weight: Polynomial, pub cell_covered_weight: Polynomial, pub t_slot_weight: Polynomial, + pub t_slot_special_weight: Polynomial, pub b2b_weight: Polynomial, pub combo_weight: Polynomial, pub damage_weight: Polynomial, pub clear_weight: Polynomial, + + pub waste_t_weight: f32, + pub tspin_reward: f32, + pub tspin_reward_expo: f32, } impl Default for Weights { @@ -23,15 +29,21 @@ impl Default for Weights { height_weight: Polynomial::new(vec![0.0, -20.0, 0.2, 0.4]), adjacent_height_differences_weight: Polynomial::new(vec![0.0, 3.0, 2.0]), total_height_difference_weight: Polynomial::new(vec![0.0, 0.0, 0.0]), - num_hole_total_weight: Polynomial::new(vec![0.0, 30.0, 5.0]), - num_hole_weighted_weight: Polynomial::new(vec![0.0, 10.0, 3.0]), + num_hole_total_weight: Polynomial::new(vec![0.0, 10.0, 3.0]), + num_hole_weighted_weight: Polynomial::new(vec![0.0, 30.0, 5.0]), + holes_per_row_weighted_weight: Polynomial::new(vec![0.0, -100.0, 100.0]), cell_covered_weight: Polynomial::new(vec![0.0, 5.0]), - t_slot_weight: Polynomial::new(vec![0.0, -500.0, 150.0]), + t_slot_weight: Polynomial::new(vec![0.0, -400.0, 120.0]), + t_slot_special_weight: Polynomial::new(vec![0.0, 0.0, 0.0]), b2b_weight: Polynomial::new(vec![0.0, -40.0, 2.0]), - combo_weight: Polynomial::new(vec![0.0, 20.0, -8.0, -0.5]), + combo_weight: Polynomial::new(vec![0.0, 20.0, -2.0, -1.0]), damage_weight: Polynomial::new(vec![0.0, 25.0, -8.0, -1.5]), clear_weight: Polynomial::new(vec![0.0, -20.0]), + + waste_t_weight: 600.0, + tspin_reward: 300.0, + tspin_reward_expo: 2.0, } } } \ No newline at end of file From b804793c5df3adc787987c15e91620fc89a08046 Mon Sep 17 00:00:00 2001 From: E12345EE12345E <60201680+E12345EE12345E@users.noreply.github.com> Date: Sun, 6 Aug 2023 17:58:18 -0700 Subject: [PATCH 06/10] panic feature + some other stuff the "some other stuff" means i dont remember what i added also use a previous version if this bot doesnt play as efficiently, still trying to figure out optimal weights given the new ones i added --- tetris/Cargo.lock | 5 +-- tetris/Cargo.toml | 3 +- tetris/src/board.rs | 60 ++++++++++++++++++++++++++++-------- tetris/src/bot.rs | 66 ++++++++++++++++++++++++++++------------ tetris/src/constants.rs | 4 +-- tetris/src/localdata.txt | 2 +- tetris/src/main.rs | 1 + tetris/src/players.rs | 4 +++ tetris/src/queue.rs | 2 +- tetris/src/weight.rs | 31 ++++++++++++++++--- 10 files changed, 135 insertions(+), 43 deletions(-) diff --git a/tetris/Cargo.lock b/tetris/Cargo.lock index 513b5e7..3c21855 100644 --- a/tetris/Cargo.lock +++ b/tetris/Cargo.lock @@ -261,9 +261,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] @@ -655,6 +655,7 @@ dependencies = [ "itertools", "log", "num", + "num_cpus", "polynomial", "rand", "serde", diff --git a/tetris/Cargo.toml b/tetris/Cargo.toml index 7814446..cb8197c 100644 --- a/tetris/Cargo.toml +++ b/tetris/Cargo.toml @@ -7,9 +7,10 @@ edition = "2021" [dependencies] rand = "0.8.5" polynomial = "0.2.4" -itertools = "0.10.5" +itertools = "0.11.0" colored = "2.0.4" num = "0.4.1" +num_cpus = "1.0" tungstenite = "*" serde = { version = "1.0.78", features = ["derive"] } diff --git a/tetris/src/board.rs b/tetris/src/board.rs index 641b9d4..eddc993 100644 --- a/tetris/src/board.rs +++ b/tetris/src/board.rs @@ -9,16 +9,20 @@ use std::fmt::{Display, Formatter}; use colored::*; use num::clamp; use crate::weight::Weights; +use crate::constants::localbotgameplay::*; +use std::fs; #[derive(Debug, Clone)] pub struct Board { arr: BoardArray, + garbage_in_queue: usize, } impl Default for Board { fn default() -> Self { Self { - arr: [0; BOARD_WIDTH] + arr: [0; BOARD_WIDTH], + garbage_in_queue: 0, } } } @@ -351,7 +355,7 @@ impl Board { } } finalcount += holes_count_weighted as f32; - println!("row {} has {} weighted holes", row, holes_count_weighted); + println!("row {} has {} weighted holes, {} holes", row, holes_count_weighted, holes_count_total); holes_count_total = 0; holes_count_weighted = 0; } @@ -374,7 +378,16 @@ impl Board { // 0 0 0 // 1 0 1 - arr == [0b101, 0b000, 0b001] || arr == [0b001, 0b000, 0b101] || arr == [0b101, 0b000, 0b101] + // 1 0 1 + // 1 0 0 + // 1 0 1 + + // 1 0 1 + // 0 0 1 + // 1 0 1 + + arr == [0b101, 0b000, 0b001] || arr == [0b001, 0b000, 0b101] || arr == [0b101, 0b000, 0b101] || + arr == [0b111, 0b000, 0b101] || arr == [0b101, 0b000, 0b111] } fn check_special_t(arr: Vec) -> bool { // special tspins @@ -420,11 +433,11 @@ impl Board { } let mut out = 0; - for row in l..(h-3) { - let mask = 0b111 << row; + for row in l..=(h-3) { + let mask = 0b111; for columns in self.arr.windows(3) { // create a 3x3 grid - let columns: Vec = columns.iter().map(|x| x & mask).collect(); + let columns: Vec = columns.iter().map(|x| x >> row & mask).collect(); // checks if it is a t slot out += Board::check_hor_t(columns) as usize; @@ -435,11 +448,11 @@ impl Board { return out } - for row in l..(h-5) { - let mask = 0b11111 << row; + for row in l..=(h-5) { + let mask = 0b11111; for columns in self.arr.windows(5) { // create a 5x5 grid - let columns: Vec = columns.iter().map(|x| x & mask).collect(); + let columns: Vec = columns.iter().map(|x| x >> row & mask).collect(); // checks if it is a t slot out += Board::check_special_t(columns) as usize; @@ -457,11 +470,11 @@ impl Board { } let mut out = 0; - for row in l..(h-5) { - let mask = 0b11111 << row; + for row in l..=(h-5) { + let mask = 0b11111; for columns in self.arr.windows(5) { // create a 5x5 grid - let columns: Vec = columns.iter().map(|x| x & mask).collect(); + let columns: Vec = columns.iter().map(|x| x >> row & mask).collect(); // checks if it is a t slot out += Board::check_special_t(columns) as usize; @@ -505,6 +518,29 @@ impl Board { return out; } + pub fn should_panic(&self) -> bool { + if self.get_max_height() + self.garbage_in_queue > 10 { + return true; + } + false + } + + pub fn garbage_in_queue_amnt(&self) -> usize { + self.garbage_in_queue + } + + pub fn get_garbage_in_queue(&self) -> usize { + let mut garbage = 0; + if ALLOWLOCALGAMEPLAY { + garbage = fs::read_to_string(LOCALGAMEPLAYFILEPATH).expect("e").chars().nth(BOTNUM).expect("e").to_string().parse::().unwrap(); + } + garbage + } + + pub fn update_board_garbage_amount(&mut self) { + self.garbage_in_queue = self.get_garbage_in_queue(); + } + // other pub fn display_with_active(&self, active_piece: &Piece) -> String { let mut out = String::new(); diff --git a/tetris/src/bot.rs b/tetris/src/bot.rs index 837d2e8..c3673f5 100644 --- a/tetris/src/bot.rs +++ b/tetris/src/bot.rs @@ -17,7 +17,7 @@ use itertools::{izip, Itertools}; use crate::communications::Suggestion; use crate::{Dependency, Opener, OpenerStatus, Point}; use crate::book::openers; -use crate::constants::board_constants::BOARD_WIDTH; +use crate::constants::board_constants::{BOARD_WIDTH, MAX_PLACE_HEIGHT}; use crate::constants::queue_constants::MIN_QUEUE_LENGTH; use crate::point_vector::PointVector; use num::clamp; @@ -27,7 +27,7 @@ use num::traits::Pow; pub struct Bot { game: Game, weight: Weights, - opener: Opener + opener: Opener, } impl Display for Bot { @@ -103,6 +103,7 @@ impl Player for Bot { // println!("{:?}", action); // println!("{}", min_score); // println!("{}", p[0]); + // println!("{:?}", p); if min_score < -10000.0{ println!("{:?}", p); } @@ -168,7 +169,7 @@ impl Bot { pub fn move_placement_score( &mut self, - depth: usize, + mut depth: usize, weights: &Weights, ) -> (MoveList, Vec, ScoreList) { let mut dummy = self.game.clone(); @@ -186,7 +187,8 @@ impl Bot { let mut next_scores = ScoreList::new(); //pruning parameters - let n = 400; + let n = 1000 - 600*self.game.board.should_panic() as usize; + if self.game.board.should_panic() { depth = depth / 2; } let prune_depth = 1; for curr_depth in 1..depth { @@ -204,7 +206,7 @@ impl Bot { .unzip(); curr_scores.sort_by(|(v1, b1), (v2, b2)| (v1 + b1).partial_cmp(&(v2 + b2)).unwrap()); - curr_scores.truncate(1 + n - n * curr_depth / depth); + curr_scores.truncate(1 + n - n * (4*curr_depth) / (5*depth)); } //generating next_mps @@ -433,7 +435,7 @@ impl Bot { //TODO: put all the logic in nice places (scorer class?) // PC (pseudo) PRUNING - if false && (game.board.get_mino_count() % 2 == 0) { + /*if false && (game.board.get_mino_count() % 2 == 0) { // pseudo pruning, gives a large penalty for unsolvable/hard to solve boards let penalty = (100.0, Bot::score_board(&game, &game.board, weights)); @@ -470,11 +472,11 @@ impl Bot { if parity.1 == false && !(usable_queue.contains(&1) || usable_queue.contains(&5) || usable_queue.contains(&6) || !game.board.get_min_height() >= 2){ return penalty } - } + }*/ return ( Bot::score_board(&game, &game.board, weights), - Bot::score_versus(&game.game_data, weights), + Bot::score_versus(&game.game_data, &game.board, weights), ) } @@ -482,14 +484,20 @@ impl Bot { Bot::get_holes_and_cell_covered_score(board, weights) + Bot::get_height_score(board, weights) + Bot::get_height_differences_score(board, weights) - + Bot::get_t_slot_score(game, board, weights) + + Bot::get_t_slot_score(game, board, weights, board.should_panic()) + + Bot::top_of_board_score(game, board) } - fn score_versus(game_data: &GameData, weight: &Weights) -> Score { + fn score_versus(game_data: &GameData, board: &Board, weight: &Weights) -> Score { // let spin = Game::get_t_spin_type(piece, board); - let combo_score = weight.combo_weight.eval(game_data.combo as f32); - let b2b = weight.b2b_weight.eval(game_data.b2b as f32); - let attack = weight.damage_weight.eval(game_data.last_sent as f32); + let mut combo_score = weight.combo_weight.eval(game_data.combo as f32); + let mut b2b = weight.b2b_weight.eval(game_data.b2b as f32); + let mut attack = weight.damage_weight.eval(game_data.last_sent as f32); + if board.should_panic() { + combo_score = weight.panic_combo_weight.eval(game_data.combo as f32); + b2b = weight.panic_b2b_weight.eval(game_data.b2b as f32); + attack = weight.panic_damage_weight.eval(game_data.last_sent as f32); + } let clear = weight.clear_weight.eval(game_data.last_cleared as f32); let pc = game_data.all_clear; let t_spin = game_data.t_spin; @@ -501,13 +509,18 @@ impl Bot { } if t_spin { extra -= weight.tspin_reward*weight.tspin_reward_expo.pow(game_data.last_cleared as f32); + if board.should_panic() { + extra -= weight.panic_tspin_reward*weight.panic_tspin_reward_expo.pow(game_data.last_cleared as f32); + } } if game_data.last_placed_piece.get_type() == 6 { + let mut wtw = weight.waste_t_weight; + if board.should_panic() { wtw = weight.panic_waste_t_weight; } match game_data.t_spin_type { - 0 => extra += weight.waste_t_weight, - 1 => extra += weight.waste_t_weight * clamp(2 - game_data.last_cleared, 0, 1) as f32, // doubles and triples should not be punished - 2 => extra += weight.waste_t_weight * 0.8 * clamp(2 - game_data.last_cleared, 0, 1) as f32, // minis should be punished less but not by much - _ => extra += weight.waste_t_weight, // idk + 0 => extra += wtw, + 1 => extra += wtw * clamp(2 - game_data.last_cleared, 0, 1) as f32, // doubles and triples should not be punished + 2 => extra += wtw * 0.9 * clamp(2 - game_data.last_cleared, 0, 1) as f32, // minis should be punished less but not by much + _ => extra += wtw, // idk } } @@ -528,9 +541,24 @@ impl Bot { adjacent_score + total_score } - pub(crate) fn get_t_slot_score(game: &Game, board: &Board, weight: &Weights) -> f32 { + fn top_of_board_score(game: &Game, board: &Board) -> f32 { + if + board.get_max_height() > MAX_PLACE_HEIGHT || + (board.get_max_height() + board.garbage_in_queue_amnt() > MAX_PLACE_HEIGHT && game.game_data.combo == 0) + { + return 1000000.0 + } + 0.0 + } + + pub(crate) fn get_t_slot_score(game: &Game, board: &Board, weight: &Weights, panic: bool) -> f32 { + if game.nearest_tpiece() == 0 { + return 10.0; + } + if panic { + return weight.panic_t_slot_weight.eval(board.t_slot() as f32) * (1.0 - (game.nearest_tpiece() as f32 / MIN_QUEUE_LENGTH as f32)); + } weight.t_slot_weight.eval(board.t_slot() as f32) * (1.0 - (game.nearest_tpiece() as f32 / MIN_QUEUE_LENGTH as f32)) - // + weight.t_slot_special_weight.eval(board.special_t_slot() as f32) } fn get_height_score(board: &Board, weight: &Weights) -> f32 { diff --git a/tetris/src/constants.rs b/tetris/src/constants.rs index 92ae2fc..f14b97d 100644 --- a/tetris/src/constants.rs +++ b/tetris/src/constants.rs @@ -92,7 +92,7 @@ pub mod versus_constants { } pub mod queue_constants { - pub const MIN_QUEUE_LENGTH: usize = 10; + pub const MIN_QUEUE_LENGTH: usize = 13; // lehmer RNG (MINSTD) pub const MULTIPLIER: usize = 16807; @@ -164,7 +164,7 @@ pub mod bot_constants { // Game::active_drop, ]; - pub const MOVEPLACEMENTSCORE: usize = 14; + pub const MOVEPLACEMENTSCORE: usize = 7; pub const PANICBURST: usize = 0; // test and will likely not be the function used later } diff --git a/tetris/src/localdata.txt b/tetris/src/localdata.txt index 857f065..c5b431b 100644 --- a/tetris/src/localdata.txt +++ b/tetris/src/localdata.txt @@ -1 +1 @@ -00 \ No newline at end of file +50 \ No newline at end of file diff --git a/tetris/src/main.rs b/tetris/src/main.rs index b2ebd7f..ab33d14 100644 --- a/tetris/src/main.rs +++ b/tetris/src/main.rs @@ -145,6 +145,7 @@ fn test_tspinkicks() { thread::sleep(time::Duration::from_millis(0)); // println!("{}", bot.get_game()); println!("{}", bot.get_game()); + println!("{}", bot.get_game().game_data.t_spin_type); println!("{} milliseconds to move", format!("{}", now.elapsed().as_micros() / 1000).green()); println!("{} lines sent / {} pieces placed = {} app", format!("{}", bot.get_game().game_data.lines_sent).green(), format!("{}", bot.get_game().game_data.pieces_placed).green(), format!("{}", (bot.get_game().game_data.lines_sent as f64) / (bot.get_game().game_data.pieces_placed as f64)).green()); println!("{} b2b, {} combo", format!("{}", bot.get_game().game_data.b2b).green(), format!("{}", bot.get_game().game_data.combo).green()) diff --git a/tetris/src/players.rs b/tetris/src/players.rs index c45259b..7f62f21 100644 --- a/tetris/src/players.rs +++ b/tetris/src/players.rs @@ -8,6 +8,7 @@ use num::clamp; use std::fs; use std::string::*; use crate::constants::localbotgameplay::*; +use std::{thread, time}; pub trait Player { fn get_game(&self) -> &Game; @@ -36,6 +37,8 @@ pub trait Player { // println!("{}", &clamped_lines_sent.to_string()); } + self.get_game_mut().board.update_board_garbage_amount(); + // println!("{}", clamped_lines_sent) // println!("{}", self.get_game().game_data.last_sent); true @@ -95,6 +98,7 @@ pub fn do_command(game: &mut Game, command: Command) -> bool { true } Command::HardDrop => { + // println!("{}", game); let game_over = !game.hard_drop(); game.set_game_over(game_over); true diff --git a/tetris/src/queue.rs b/tetris/src/queue.rs index 2bc12b3..f0f3df8 100644 --- a/tetris/src/queue.rs +++ b/tetris/src/queue.rs @@ -56,7 +56,7 @@ impl PieceQueue { } pub fn next(&mut self) -> Piece { - if self.queue.len() <= MIN_QUEUE_LENGTH { + while self.queue.len() <= MIN_QUEUE_LENGTH { self.next_bag(); } diff --git a/tetris/src/weight.rs b/tetris/src/weight.rs index 13c61b8..80e0f8e 100644 --- a/tetris/src/weight.rs +++ b/tetris/src/weight.rs @@ -12,31 +12,40 @@ pub struct Weights { pub cell_covered_weight: Polynomial, pub t_slot_weight: Polynomial, - pub t_slot_special_weight: Polynomial, pub b2b_weight: Polynomial, pub combo_weight: Polynomial, pub damage_weight: Polynomial, pub clear_weight: Polynomial, + pub panic_t_slot_weight: Polynomial, + pub panic_b2b_weight: Polynomial, + pub panic_combo_weight: Polynomial, + pub panic_damage_weight: Polynomial, + pub waste_t_weight: f32, pub tspin_reward: f32, pub tspin_reward_expo: f32, + + pub panic_waste_t_weight: f32, + pub panic_tspin_reward: f32, + pub panic_tspin_reward_expo: f32, } impl Default for Weights { fn default() -> Self { Self { - height_weight: Polynomial::new(vec![0.0, -20.0, 0.2, 0.4]), + // Default + + height_weight: Polynomial::new(vec![0.0, -40.0, 0.4, 0.8]), adjacent_height_differences_weight: Polynomial::new(vec![0.0, 3.0, 2.0]), total_height_difference_weight: Polynomial::new(vec![0.0, 0.0, 0.0]), num_hole_total_weight: Polynomial::new(vec![0.0, 10.0, 3.0]), num_hole_weighted_weight: Polynomial::new(vec![0.0, 30.0, 5.0]), holes_per_row_weighted_weight: Polynomial::new(vec![0.0, -100.0, 100.0]), cell_covered_weight: Polynomial::new(vec![0.0, 5.0]), + t_slot_weight: Polynomial::new(vec![0.0, -400.0, 80.0]), - t_slot_weight: Polynomial::new(vec![0.0, -400.0, 120.0]), - t_slot_special_weight: Polynomial::new(vec![0.0, 0.0, 0.0]), - b2b_weight: Polynomial::new(vec![0.0, -40.0, 2.0]), + b2b_weight: Polynomial::new(vec![0.0, -30.0, -2.0]), combo_weight: Polynomial::new(vec![0.0, 20.0, -2.0, -1.0]), damage_weight: Polynomial::new(vec![0.0, 25.0, -8.0, -1.5]), clear_weight: Polynomial::new(vec![0.0, -20.0]), @@ -44,6 +53,18 @@ impl Default for Weights { waste_t_weight: 600.0, tspin_reward: 300.0, tspin_reward_expo: 2.0, + + // Panic + + panic_t_slot_weight: Polynomial::new(vec![0.0, -40.0, 20.0]), + + panic_b2b_weight: Polynomial::new(vec![0.0]), + panic_combo_weight: Polynomial::new(vec![0.0, 10.0, -8.0, -1.5]), + panic_damage_weight: Polynomial::new(vec![0.0, 25.0, -2.0, -1.5]), + + panic_waste_t_weight: 10.0, + panic_tspin_reward: 100.0, + panic_tspin_reward_expo: 1.0, } } } \ No newline at end of file From bfa64aa0838635178e5fc6d8df3dc459043c3227 Mon Sep 17 00:00:00 2001 From: E12345EE12345E <60201680+E12345EE12345E@users.noreply.github.com> Date: Tue, 8 Aug 2023 14:24:59 -0700 Subject: [PATCH 07/10] bot paranoia paranoia is calculated by the same factors that cause my hands to get sweaty watching the bot gameplay --- tetris/src/board.rs | 27 ---------------------- tetris/src/bot.rs | 38 ++++++++++++++++++------------ tetris/src/game.rs | 50 ++++++++++++++++++++++++++++++++++++++++ tetris/src/localdata.txt | 2 +- tetris/src/main.rs | 2 ++ tetris/src/players.rs | 2 -- tetris/src/queue.rs | 13 +++++++++-- tetris/src/weight.rs | 31 ++++++++++++++----------- 8 files changed, 105 insertions(+), 60 deletions(-) diff --git a/tetris/src/board.rs b/tetris/src/board.rs index eddc993..003145e 100644 --- a/tetris/src/board.rs +++ b/tetris/src/board.rs @@ -9,20 +9,16 @@ use std::fmt::{Display, Formatter}; use colored::*; use num::clamp; use crate::weight::Weights; -use crate::constants::localbotgameplay::*; -use std::fs; #[derive(Debug, Clone)] pub struct Board { arr: BoardArray, - garbage_in_queue: usize, } impl Default for Board { fn default() -> Self { Self { arr: [0; BOARD_WIDTH], - garbage_in_queue: 0, } } } @@ -518,29 +514,6 @@ impl Board { return out; } - pub fn should_panic(&self) -> bool { - if self.get_max_height() + self.garbage_in_queue > 10 { - return true; - } - false - } - - pub fn garbage_in_queue_amnt(&self) -> usize { - self.garbage_in_queue - } - - pub fn get_garbage_in_queue(&self) -> usize { - let mut garbage = 0; - if ALLOWLOCALGAMEPLAY { - garbage = fs::read_to_string(LOCALGAMEPLAYFILEPATH).expect("e").chars().nth(BOTNUM).expect("e").to_string().parse::().unwrap(); - } - garbage - } - - pub fn update_board_garbage_amount(&mut self) { - self.garbage_in_queue = self.get_garbage_in_queue(); - } - // other pub fn display_with_active(&self, active_piece: &Piece) -> String { let mut out = String::new(); diff --git a/tetris/src/bot.rs b/tetris/src/bot.rs index c3673f5..f935c2f 100644 --- a/tetris/src/bot.rs +++ b/tetris/src/bot.rs @@ -187,8 +187,8 @@ impl Bot { let mut next_scores = ScoreList::new(); //pruning parameters - let n = 1000 - 600*self.game.board.should_panic() as usize; - if self.game.board.should_panic() { depth = depth / 2; } + let mut n = 1600 - clamp(self.game.get_paranoia(), 0.0, 2.0) as usize * 400; + if self.game.should_panic() { n = 200; } let prune_depth = 1; for curr_depth in 1..depth { @@ -476,24 +476,24 @@ impl Bot { return ( Bot::score_board(&game, &game.board, weights), - Bot::score_versus(&game.game_data, &game.board, weights), + Bot::score_versus(&game, &game.game_data, weights), ) } fn score_board(game: &Game, board: &Board, weights: &Weights) -> Score { - Bot::get_holes_and_cell_covered_score(board, weights) - + Bot::get_height_score(board, weights) + Bot::get_holes_and_cell_covered_score(board, weights, game.should_panic()) + + Bot::get_height_score(board, weights, game.should_panic()) + Bot::get_height_differences_score(board, weights) - + Bot::get_t_slot_score(game, board, weights, board.should_panic()) + + Bot::get_t_slot_score(game, board, weights, game.should_panic()) + Bot::top_of_board_score(game, board) } - fn score_versus(game_data: &GameData, board: &Board, weight: &Weights) -> Score { + fn score_versus(game: &Game, game_data: &GameData, weight: &Weights) -> Score { // let spin = Game::get_t_spin_type(piece, board); let mut combo_score = weight.combo_weight.eval(game_data.combo as f32); let mut b2b = weight.b2b_weight.eval(game_data.b2b as f32); let mut attack = weight.damage_weight.eval(game_data.last_sent as f32); - if board.should_panic() { + if game.should_panic() { combo_score = weight.panic_combo_weight.eval(game_data.combo as f32); b2b = weight.panic_b2b_weight.eval(game_data.b2b as f32); attack = weight.panic_damage_weight.eval(game_data.last_sent as f32); @@ -501,6 +501,7 @@ impl Bot { let clear = weight.clear_weight.eval(game_data.last_cleared as f32); let pc = game_data.all_clear; let t_spin = game_data.t_spin; + let paranoia = game.get_paranoia() * weight.paranoia_weight; let mut extra = 0.0; @@ -509,13 +510,13 @@ impl Bot { } if t_spin { extra -= weight.tspin_reward*weight.tspin_reward_expo.pow(game_data.last_cleared as f32); - if board.should_panic() { + if game.should_panic() { extra -= weight.panic_tspin_reward*weight.panic_tspin_reward_expo.pow(game_data.last_cleared as f32); } } if game_data.last_placed_piece.get_type() == 6 { let mut wtw = weight.waste_t_weight; - if board.should_panic() { wtw = weight.panic_waste_t_weight; } + if game.should_panic() { wtw = weight.panic_waste_t_weight; } match game_data.t_spin_type { 0 => extra += wtw, 1 => extra += wtw * clamp(2 - game_data.last_cleared, 0, 1) as f32, // doubles and triples should not be punished @@ -524,7 +525,7 @@ impl Bot { } } - combo_score + b2b + attack + clear + extra + combo_score + b2b + attack + clear + paranoia + extra } fn get_height_differences_score(board: &Board, weight: &Weights) -> f32 { @@ -544,7 +545,7 @@ impl Bot { fn top_of_board_score(game: &Game, board: &Board) -> f32 { if board.get_max_height() > MAX_PLACE_HEIGHT || - (board.get_max_height() + board.garbage_in_queue_amnt() > MAX_PLACE_HEIGHT && game.game_data.combo == 0) + (board.get_max_height() + game.game_data.garbage_in_queue > MAX_PLACE_HEIGHT && game.game_data.combo == 0) { return 1000000.0 } @@ -561,17 +562,24 @@ impl Bot { weight.t_slot_weight.eval(board.t_slot() as f32) * (1.0 - (game.nearest_tpiece() as f32 / MIN_QUEUE_LENGTH as f32)) } - fn get_height_score(board: &Board, weight: &Weights) -> f32 { + fn get_height_score(board: &Board, weight: &Weights, panic: bool) -> f32 { let total_height = board.get_max_height(); + if panic { + return weight.panic_height_weight.eval(total_height as f32); + } weight.height_weight.eval(total_height as f32) } - fn get_holes_and_cell_covered_score(board: &Board, weight: &Weights) -> f32 { + fn get_holes_and_cell_covered_score(board: &Board, weight: &Weights, panic: bool) -> f32 { let mut out = 0.0; let (holes_t, holes_w, covered) = board.holes_cell_covered(); - out += weight.num_hole_total_weight.eval(holes_t as f32); + if panic { + out += weight.panic_num_hole_total_weight.eval(holes_t as f32); + } else { + out += weight.num_hole_total_weight.eval(holes_t as f32); + } out += weight.num_hole_weighted_weight.eval(holes_w as f32); out += weight.cell_covered_weight.eval(covered as f32); out += board.horizontal_holes_weighted(weight); diff --git a/tetris/src/game.rs b/tetris/src/game.rs index 96fbd9c..68ee0bb 100644 --- a/tetris/src/game.rs +++ b/tetris/src/game.rs @@ -13,6 +13,11 @@ use game_rules_and_data::*; use std::fmt::{Display, Formatter}; use crate::game::game_rules_and_data::SpinBonus::TSpin; use colored::*; +use crate::constants::localbotgameplay::*; +use std::fs; +use crate::constants::board_constants::MAX_PLACE_HEIGHT; +use crate::constants::queue_constants::MIN_QUEUE_LENGTH; +use num::clamp; #[derive(Default, Clone)] pub struct Game { @@ -296,6 +301,48 @@ impl Game { self.piece_queue.nearest_tpiece() } + pub fn nearest_ipiece(&self) -> usize { + if self.hold_piece == Some(4) || self.active_piece.get_type() == 4 { + return 0; + } + self.piece_queue.nearest_ipiece() + } + + pub fn should_panic(&self) -> bool { + if + self.board.get_max_height() + self.game_data.garbage_in_queue > MAX_PLACE_HEIGHT / 2 && !self.game_data.panic || + self.game_data.combo > 0 && self.game_data.panic || + self.board.get_max_height() > MAX_PLACE_HEIGHT / 2 && self.game_data.panic + { + return true; + } + false + } + + pub fn get_paranoia(&self) -> f32 { + if self.should_panic() { + return 0.0; + } + + let (holes_count_total, holes_count_weighted, _) = self.board.holes_cell_covered(); + + (clamp(2.0 * self.board.get_max_height() as f32 / MAX_PLACE_HEIGHT as f32, 0.1, 1.0) * self.nearest_ipiece() as f32) + + (holes_count_total as f32 / 20.0 + holes_count_weighted as f32 / 8.0) + } + + pub fn get_garbage_in_queue(&self) -> usize { + let mut garbage = 0; + if ALLOWLOCALGAMEPLAY { + garbage = fs::read_to_string(LOCALGAMEPLAYFILEPATH).expect("e").chars().nth(BOTNUM).expect("e").to_string().parse::().unwrap(); + } + garbage + } + + pub fn update_garbage_amount(&mut self) { + self.game_data.garbage_in_queue = self.get_garbage_in_queue(); + self.game_data.panic = self.should_panic(); + } + pub fn update(&mut self) { let t_spin_type = Game::get_t_spin_type(&self.active_piece, &self.board); let lines_cleared = self.board.clear_lines(); @@ -328,6 +375,9 @@ pub mod game_rules_and_data { pub t_spin_type: u16, pub game_over: bool, + + pub panic: bool, + pub garbage_in_queue: usize, } impl GameData { diff --git a/tetris/src/localdata.txt b/tetris/src/localdata.txt index c5b431b..aa2f0b2 100644 --- a/tetris/src/localdata.txt +++ b/tetris/src/localdata.txt @@ -1 +1 @@ -50 \ No newline at end of file +09 \ No newline at end of file diff --git a/tetris/src/main.rs b/tetris/src/main.rs index ab33d14..e818331 100644 --- a/tetris/src/main.rs +++ b/tetris/src/main.rs @@ -88,6 +88,7 @@ fn bot_play_local() { let mut time = 0; while !bot.get_game().get_game_over() && bot.get_game().game_data.pieces_placed < 10000 { let now = time::Instant::now(); + bot.get_game_mut().update_garbage_amount(); bot.make_move(); time += now.elapsed().as_micros(); @@ -102,6 +103,7 @@ fn bot_play_local() { thread::sleep(time::Duration::from_millis(0)); // println!("{}", bot.get_game()); println!("{}", bot.get_game()); + println!("{}", bot.get_game().get_paranoia()); println!("{} milliseconds to move", format!("{}", now.elapsed().as_micros() / 1000).green()); println!("{} lines sent / {} pieces placed = {} app", format!("{}", bot.get_game().game_data.lines_sent).green(), format!("{}", bot.get_game().game_data.pieces_placed).green(), format!("{}", (bot.get_game().game_data.lines_sent as f64) / (bot.get_game().game_data.pieces_placed as f64)).green()); println!("{} b2b, {} combo", format!("{}", bot.get_game().game_data.b2b).green(), format!("{}", bot.get_game().game_data.combo).green()) diff --git a/tetris/src/players.rs b/tetris/src/players.rs index 7f62f21..078fea1 100644 --- a/tetris/src/players.rs +++ b/tetris/src/players.rs @@ -37,8 +37,6 @@ pub trait Player { // println!("{}", &clamped_lines_sent.to_string()); } - self.get_game_mut().board.update_board_garbage_amount(); - // println!("{}", clamped_lines_sent) // println!("{}", self.get_game().game_data.last_sent); true diff --git a/tetris/src/queue.rs b/tetris/src/queue.rs index f0f3df8..b88d346 100644 --- a/tetris/src/queue.rs +++ b/tetris/src/queue.rs @@ -123,10 +123,19 @@ impl PieceQueue { pub fn nearest_tpiece(&self) -> usize { for piece in 0..MIN_QUEUE_LENGTH { if self.queue[piece] == 6 { - return piece; + return piece + 1; } } - return MIN_QUEUE_LENGTH; + return MIN_QUEUE_LENGTH + 1; + } + + pub fn nearest_ipiece(&self) -> usize { + for piece in 0..MIN_QUEUE_LENGTH { + if self.queue[piece] == 4 { + return piece + 1; + } + } + return MIN_QUEUE_LENGTH + 1; } } diff --git a/tetris/src/weight.rs b/tetris/src/weight.rs index 80e0f8e..7e612c2 100644 --- a/tetris/src/weight.rs +++ b/tetris/src/weight.rs @@ -10,22 +10,24 @@ pub struct Weights { pub num_hole_weighted_weight: Polynomial, pub holes_per_row_weighted_weight: Polynomial, pub cell_covered_weight: Polynomial, - pub t_slot_weight: Polynomial, + pub b2b_weight: Polynomial, pub combo_weight: Polynomial, pub damage_weight: Polynomial, pub clear_weight: Polynomial, - pub panic_t_slot_weight: Polynomial, - pub panic_b2b_weight: Polynomial, - pub panic_combo_weight: Polynomial, - pub panic_damage_weight: Polynomial, - pub waste_t_weight: f32, pub tspin_reward: f32, pub tspin_reward_expo: f32, + pub paranoia_weight: f32, + pub panic_height_weight: Polynomial, + pub panic_num_hole_total_weight: Polynomial, + pub panic_t_slot_weight: Polynomial, + pub panic_b2b_weight: Polynomial, + pub panic_combo_weight: Polynomial, + pub panic_damage_weight: Polynomial, pub panic_waste_t_weight: f32, pub panic_tspin_reward: f32, pub panic_tspin_reward_expo: f32, @@ -36,34 +38,37 @@ impl Default for Weights { Self { // Default - height_weight: Polynomial::new(vec![0.0, -40.0, 0.4, 0.8]), + height_weight: Polynomial::new(vec![0.0, -20.0, 0.2, 0.4]), adjacent_height_differences_weight: Polynomial::new(vec![0.0, 3.0, 2.0]), total_height_difference_weight: Polynomial::new(vec![0.0, 0.0, 0.0]), num_hole_total_weight: Polynomial::new(vec![0.0, 10.0, 3.0]), num_hole_weighted_weight: Polynomial::new(vec![0.0, 30.0, 5.0]), holes_per_row_weighted_weight: Polynomial::new(vec![0.0, -100.0, 100.0]), - cell_covered_weight: Polynomial::new(vec![0.0, 5.0]), - t_slot_weight: Polynomial::new(vec![0.0, -400.0, 80.0]), + cell_covered_weight: Polynomial::new(vec![0.0, 4.0]), + t_slot_weight: Polynomial::new(vec![0.0, -800.0, 160.0]), b2b_weight: Polynomial::new(vec![0.0, -30.0, -2.0]), - combo_weight: Polynomial::new(vec![0.0, 20.0, -2.0, -1.0]), + combo_weight: Polynomial::new(vec![0.0, 40.0, -2.0, -1.0]), damage_weight: Polynomial::new(vec![0.0, 25.0, -8.0, -1.5]), clear_weight: Polynomial::new(vec![0.0, -20.0]), waste_t_weight: 600.0, tspin_reward: 300.0, tspin_reward_expo: 2.0, + paranoia_weight: 80.0, // Panic + panic_height_weight: Polynomial::new(vec![0.0, 80.0, 1.0, 1.0]), + panic_num_hole_total_weight: Polynomial::new(vec![0.0, 100.0, 3.0]), panic_t_slot_weight: Polynomial::new(vec![0.0, -40.0, 20.0]), panic_b2b_weight: Polynomial::new(vec![0.0]), - panic_combo_weight: Polynomial::new(vec![0.0, 10.0, -8.0, -1.5]), - panic_damage_weight: Polynomial::new(vec![0.0, 25.0, -2.0, -1.5]), + panic_combo_weight: Polynomial::new(vec![0.0, 20.0, -16.0, -2.5]), + panic_damage_weight: Polynomial::new(vec![0.0, 40.0, -12.0, -2.0]), panic_waste_t_weight: 10.0, - panic_tspin_reward: 100.0, + panic_tspin_reward: 400.0, panic_tspin_reward_expo: 1.0, } } From b73f33f5bcf443715311d5ab6d0765e781b423a1 Mon Sep 17 00:00:00 2001 From: E12345EE12345E <60201680+E12345EE12345E@users.noreply.github.com> Date: Tue, 8 Aug 2023 15:13:55 -0700 Subject: [PATCH 08/10] idk i improved some stuff not much --- tetris/src/bot.rs | 2 +- tetris/src/game.rs | 3 ++- tetris/src/localdata.txt | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tetris/src/bot.rs b/tetris/src/bot.rs index f935c2f..eff858d 100644 --- a/tetris/src/bot.rs +++ b/tetris/src/bot.rs @@ -187,7 +187,7 @@ impl Bot { let mut next_scores = ScoreList::new(); //pruning parameters - let mut n = 1600 - clamp(self.game.get_paranoia(), 0.0, 2.0) as usize * 400; + let mut n = 1200 - clamp(self.game.get_paranoia(), 0.0, 2.0) as usize * 500; if self.game.should_panic() { n = 200; } let prune_depth = 1; diff --git a/tetris/src/game.rs b/tetris/src/game.rs index 68ee0bb..182bf34 100644 --- a/tetris/src/game.rs +++ b/tetris/src/game.rs @@ -327,7 +327,8 @@ impl Game { let (holes_count_total, holes_count_weighted, _) = self.board.holes_cell_covered(); (clamp(2.0 * self.board.get_max_height() as f32 / MAX_PLACE_HEIGHT as f32, 0.1, 1.0) * self.nearest_ipiece() as f32) + - (holes_count_total as f32 / 20.0 + holes_count_weighted as f32 / 8.0) + (holes_count_total as f32 / 20.0 + holes_count_weighted as f32 / 8.0) + + (self.nearest_ipiece() as f32 / 4.0) } pub fn get_garbage_in_queue(&self) -> usize { diff --git a/tetris/src/localdata.txt b/tetris/src/localdata.txt index aa2f0b2..857f065 100644 --- a/tetris/src/localdata.txt +++ b/tetris/src/localdata.txt @@ -1 +1 @@ -09 \ No newline at end of file +00 \ No newline at end of file From 0f72ecc2b5f167a25e76678487b5818c8b3554d4 Mon Sep 17 00:00:00 2001 From: E12345EE12345E <60201680+E12345EE12345E@users.noreply.github.com> Date: Wed, 9 Aug 2023 09:26:27 -0700 Subject: [PATCH 09/10] small changes smol --- tetris/src/bot.rs | 33 +++++++++++++++++++++++++++------ tetris/src/localdata.txt | 2 +- tetris/src/weight.rs | 2 +- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/tetris/src/bot.rs b/tetris/src/bot.rs index eff858d..55f0dc6 100644 --- a/tetris/src/bot.rs +++ b/tetris/src/bot.rs @@ -28,6 +28,7 @@ pub struct Bot { game: Game, weight: Weights, opener: Opener, + next_placements: PlacementList, } impl Display for Bot { @@ -43,6 +44,7 @@ impl Default for Bot { game: Game::new(None), weight: Weights::default(), opener: Opener::default(), + next_placements: PlacementList::new(), } } } @@ -60,6 +62,23 @@ impl Player for Bot { // R, C let mut action = vec![]; + if self.next_placements.len() > 0 { + println!("{:?}", self.next_placements); + match Bot::moves_to_placement(&mut self.get_game().clone(), &self.next_placements[0]) { + Ok(m) => { + action = m; + action.push(Command::HardDrop); + self.next_placements.remove(0); + + return action; + }, + Err(_) => { + eprintln!("error"); + self.next_placements = PlacementList::new(); + } + } + } + if self.opener.status == OpenerStatus::New { let mut sequence = vec![self.get_game().active_piece.piece_type]; sequence.append(&mut self.get_game().piece_queue.get_vec()); @@ -104,8 +123,10 @@ impl Player for Bot { // println!("{}", min_score); // println!("{}", p[0]); // println!("{:?}", p); - if min_score < -10000.0{ - println!("{:?}", p); + if min_score < -100000.0{ + self.next_placements = p; + self.next_placements.remove(0); + println!("{:?}", self.next_placements); } action.push(Command::HardDrop); @@ -187,8 +208,8 @@ impl Bot { let mut next_scores = ScoreList::new(); //pruning parameters - let mut n = 1200 - clamp(self.game.get_paranoia(), 0.0, 2.0) as usize * 500; - if self.game.should_panic() { n = 200; } + let mut n = 800 - clamp(self.game.get_paranoia(), 0.0, 4.0) as usize * 150; + if self.game.should_panic() { n = 120; } let prune_depth = 1; for curr_depth in 1..depth { @@ -506,7 +527,7 @@ impl Bot { let mut extra = 0.0; if pc { - extra -= 10000.0; + extra -= 1000000.0; } if t_spin { extra -= weight.tspin_reward*weight.tspin_reward_expo.pow(game_data.last_cleared as f32); @@ -547,7 +568,7 @@ impl Bot { board.get_max_height() > MAX_PLACE_HEIGHT || (board.get_max_height() + game.game_data.garbage_in_queue > MAX_PLACE_HEIGHT && game.game_data.combo == 0) { - return 1000000.0 + return 10000000.0 } 0.0 } diff --git a/tetris/src/localdata.txt b/tetris/src/localdata.txt index 857f065..aa2f0b2 100644 --- a/tetris/src/localdata.txt +++ b/tetris/src/localdata.txt @@ -1 +1 @@ -00 \ No newline at end of file +09 \ No newline at end of file diff --git a/tetris/src/weight.rs b/tetris/src/weight.rs index 7e612c2..0af6268 100644 --- a/tetris/src/weight.rs +++ b/tetris/src/weight.rs @@ -55,7 +55,7 @@ impl Default for Weights { waste_t_weight: 600.0, tspin_reward: 300.0, tspin_reward_expo: 2.0, - paranoia_weight: 80.0, + paranoia_weight: 40.0, // Panic From 8cc71854ad62cca698e3bd67b0e84d9ac89d198e Mon Sep 17 00:00:00 2001 From: E12345EE12345E <60201680+E12345EE12345E@users.noreply.github.com> Date: Wed, 9 Aug 2023 14:53:39 -0700 Subject: [PATCH 10/10] better weights maybe --- tetris/src/board.rs | 4 ++-- tetris/src/bot.rs | 4 ++-- tetris/src/constants.rs | 2 ++ tetris/src/game.rs | 2 ++ tetris/src/main.rs | 11 +++++++---- tetris/src/players.rs | 3 ++- tetris/src/queue.rs | 5 +++++ tetris/src/weight.rs | 16 ++++++++-------- 8 files changed, 30 insertions(+), 17 deletions(-) diff --git a/tetris/src/board.rs b/tetris/src/board.rs index 003145e..dcf2788 100644 --- a/tetris/src/board.rs +++ b/tetris/src/board.rs @@ -3,7 +3,7 @@ use crate::constants::board_constants::*; use crate::constants::types::*; use crate::piece::*; -use crate::queue::{piece_type_to_string_colored}; +use crate::queue::{piece_type_to_block_colored}; use crate::point_vector::{Point, PointVector}; use std::fmt::{Display, Formatter}; use colored::*; @@ -523,7 +523,7 @@ impl Board { if self.get(row, col) { out.push_str("■ "); } else if locations.contains(&Point(row as i8, col as i8)) { - out.push_str(&format!("{} ", piece_type_to_string_colored(active_piece.get_type()))); + out.push_str(&format!("{} ", piece_type_to_block_colored(active_piece.get_type()))); } else { out.push_str(&format!("{} ", ("▫".truecolor(clamp(8*row,0,255).try_into().unwrap(),clamp(100-4*row,0,255).try_into().unwrap(),clamp(40,0,255).try_into().unwrap())))); } diff --git a/tetris/src/bot.rs b/tetris/src/bot.rs index 55f0dc6..bc707ef 100644 --- a/tetris/src/bot.rs +++ b/tetris/src/bot.rs @@ -208,8 +208,8 @@ impl Bot { let mut next_scores = ScoreList::new(); //pruning parameters - let mut n = 800 - clamp(self.game.get_paranoia(), 0.0, 4.0) as usize * 150; - if self.game.should_panic() { n = 120; } + let mut n = 600 - clamp(self.game.get_paranoia(), 0.0, 4.0) as usize * 100; + if self.game.should_panic() { n = 80; } let prune_depth = 1; for curr_depth in 1..depth { diff --git a/tetris/src/constants.rs b/tetris/src/constants.rs index f14b97d..6031583 100644 --- a/tetris/src/constants.rs +++ b/tetris/src/constants.rs @@ -37,6 +37,8 @@ pub mod board_constants { pub const ZERO_ONE: usize = 0x5555555555; pub const ONE_ZERO: usize = 0xAAAAAAAAAA; + + pub const CONSOLE_DISPLAY_STATS: bool = true; } pub mod piece_constants { diff --git a/tetris/src/game.rs b/tetris/src/game.rs index 182bf34..6ed1579 100644 --- a/tetris/src/game.rs +++ b/tetris/src/game.rs @@ -341,6 +341,7 @@ impl Game { pub fn update_garbage_amount(&mut self) { self.game_data.garbage_in_queue = self.get_garbage_in_queue(); + self.game_data.total_garbage_recieved += self.game_data.garbage_in_queue; // will die in edge cases with garbage being sent during cancellation combos but im too lazy to accurately track this self.game_data.panic = self.should_panic(); } @@ -379,6 +380,7 @@ pub mod game_rules_and_data { pub panic: bool, pub garbage_in_queue: usize, + pub total_garbage_recieved: usize, } impl GameData { diff --git a/tetris/src/main.rs b/tetris/src/main.rs index e818331..a1baecb 100644 --- a/tetris/src/main.rs +++ b/tetris/src/main.rs @@ -24,6 +24,7 @@ use crate::board::Board; use crate::constants::types::Dependencies; use crate::constants::versus_constants::AttackType::T; use crate::constants::localbotgameplay::*; +use crate::constants::board_constants::CONSOLE_DISPLAY_STATS; use crate::game::Game; use crate::piece::Piece; use crate::weight::Weights; @@ -103,10 +104,12 @@ fn bot_play_local() { thread::sleep(time::Duration::from_millis(0)); // println!("{}", bot.get_game()); println!("{}", bot.get_game()); - println!("{}", bot.get_game().get_paranoia()); - println!("{} milliseconds to move", format!("{}", now.elapsed().as_micros() / 1000).green()); - println!("{} lines sent / {} pieces placed = {} app", format!("{}", bot.get_game().game_data.lines_sent).green(), format!("{}", bot.get_game().game_data.pieces_placed).green(), format!("{}", (bot.get_game().game_data.lines_sent as f64) / (bot.get_game().game_data.pieces_placed as f64)).green()); - println!("{} b2b, {} combo", format!("{}", bot.get_game().game_data.b2b).green(), format!("{}", bot.get_game().game_data.combo).green()) + if CONSOLE_DISPLAY_STATS { + println!("{} milliseconds to move", format!("{}", now.elapsed().as_micros() / 1000).green()); + println!("{} pps, {} apm", format!("{}", (bot.get_game().game_data.pieces_placed as f64 / (time as f64 / 1000000000.0)).round() / 1000.0).green(), format!("{}", (60.0 * bot.get_game().game_data.lines_sent as f64 / (time as f64 / 1000000000.0)).round() / 1000.0).green()); + println!("{} lines sent / {} pieces placed = {} app", format!("{}", bot.get_game().game_data.lines_sent).green(), format!("{}", bot.get_game().game_data.pieces_placed).green(), format!("{}", (bot.get_game().game_data.lines_sent as f64) / (bot.get_game().game_data.pieces_placed as f64)).green()); + println!("{} b2b, {} combo", format!("{}", bot.get_game().game_data.b2b).green(), format!("{}", bot.get_game().game_data.combo).green()); + } } println!( "Making {} moves took {} microseconds on average", diff --git a/tetris/src/players.rs b/tetris/src/players.rs index 078fea1..cc5bcfb 100644 --- a/tetris/src/players.rs +++ b/tetris/src/players.rs @@ -79,6 +79,8 @@ pub trait Player { pub fn do_move_list(game: &mut Game, commands: CommandList) { for command in commands { do_command(game, command); + // println!("{}", game); + // thread::sleep(time::Duration::from_millis(2)); } } @@ -96,7 +98,6 @@ pub fn do_command(game: &mut Game, command: Command) -> bool { true } Command::HardDrop => { - // println!("{}", game); let game_over = !game.hard_drop(); game.set_game_over(game_over); true diff --git a/tetris/src/queue.rs b/tetris/src/queue.rs index b88d346..a491a90 100644 --- a/tetris/src/queue.rs +++ b/tetris/src/queue.rs @@ -149,6 +149,11 @@ pub fn piece_type_to_string_colored(piece: PieceType) -> ColoredString { arr[piece].to_owned() } +pub fn piece_type_to_block_colored(piece: PieceType) -> ColoredString { + let arr = ["■".red(), "■".truecolor(255,128,0), "■".bright_yellow(), "■".green(), "■".bright_blue(), "■".blue(), "■".bright_purple()]; + arr[piece].to_owned() +} + impl Display for PieceQueue { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { for piece in 0..MIN_QUEUE_LENGTH { diff --git a/tetris/src/weight.rs b/tetris/src/weight.rs index 0af6268..8617d50 100644 --- a/tetris/src/weight.rs +++ b/tetris/src/weight.rs @@ -41,20 +41,20 @@ impl Default for Weights { height_weight: Polynomial::new(vec![0.0, -20.0, 0.2, 0.4]), adjacent_height_differences_weight: Polynomial::new(vec![0.0, 3.0, 2.0]), total_height_difference_weight: Polynomial::new(vec![0.0, 0.0, 0.0]), - num_hole_total_weight: Polynomial::new(vec![0.0, 10.0, 3.0]), - num_hole_weighted_weight: Polynomial::new(vec![0.0, 30.0, 5.0]), + num_hole_total_weight: Polynomial::new(vec![0.0, 4.0, 1.0]), + num_hole_weighted_weight: Polynomial::new(vec![0.0, 10.0, 2.0]), holes_per_row_weighted_weight: Polynomial::new(vec![0.0, -100.0, 100.0]), cell_covered_weight: Polynomial::new(vec![0.0, 4.0]), t_slot_weight: Polynomial::new(vec![0.0, -800.0, 160.0]), - b2b_weight: Polynomial::new(vec![0.0, -30.0, -2.0]), - combo_weight: Polynomial::new(vec![0.0, 40.0, -2.0, -1.0]), - damage_weight: Polynomial::new(vec![0.0, 25.0, -8.0, -1.5]), - clear_weight: Polynomial::new(vec![0.0, -20.0]), + b2b_weight: Polynomial::new(vec![0.0, -60.0, -2.0]), + combo_weight: Polynomial::new(vec![0.0, 60.0, -2.0, -1.0]), + damage_weight: Polynomial::new(vec![0.0, 30.0, -8.0, -1.5]), + clear_weight: Polynomial::new(vec![0.0, -5.0]), waste_t_weight: 600.0, - tspin_reward: 300.0, - tspin_reward_expo: 2.0, + tspin_reward: 100.0, + tspin_reward_expo: 4.0, paranoia_weight: 40.0, // Panic