From a104667eccff2f191e28859f200c602a25ad1181 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Wed, 9 Jul 2025 19:31:59 +0100 Subject: [PATCH 01/15] WIP --- glloyd_and_dbetteridge/.idea/.gitignore | 8 ++ .../.idea/glloyd_and_dbetteridge.iml | 11 +++ glloyd_and_dbetteridge/.idea/modules.xml | 8 ++ glloyd_and_dbetteridge/.idea/vcs.xml | 6 ++ glloyd_and_dbetteridge/Cargo.lock | 7 ++ glloyd_and_dbetteridge/Cargo.toml | 6 ++ glloyd_and_dbetteridge/src/main.rs | 84 +++++++++++++++++++ 7 files changed, 130 insertions(+) create mode 100644 glloyd_and_dbetteridge/.idea/.gitignore create mode 100644 glloyd_and_dbetteridge/.idea/glloyd_and_dbetteridge.iml create mode 100644 glloyd_and_dbetteridge/.idea/modules.xml create mode 100644 glloyd_and_dbetteridge/.idea/vcs.xml create mode 100644 glloyd_and_dbetteridge/Cargo.lock create mode 100644 glloyd_and_dbetteridge/Cargo.toml create mode 100644 glloyd_and_dbetteridge/src/main.rs diff --git a/glloyd_and_dbetteridge/.idea/.gitignore b/glloyd_and_dbetteridge/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/glloyd_and_dbetteridge/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/glloyd_and_dbetteridge/.idea/glloyd_and_dbetteridge.iml b/glloyd_and_dbetteridge/.idea/glloyd_and_dbetteridge.iml new file mode 100644 index 0000000..cf84ae4 --- /dev/null +++ b/glloyd_and_dbetteridge/.idea/glloyd_and_dbetteridge.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/glloyd_and_dbetteridge/.idea/modules.xml b/glloyd_and_dbetteridge/.idea/modules.xml new file mode 100644 index 0000000..c7d89c9 --- /dev/null +++ b/glloyd_and_dbetteridge/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/glloyd_and_dbetteridge/.idea/vcs.xml b/glloyd_and_dbetteridge/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/glloyd_and_dbetteridge/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/glloyd_and_dbetteridge/Cargo.lock b/glloyd_and_dbetteridge/Cargo.lock new file mode 100644 index 0000000..047eb40 --- /dev/null +++ b/glloyd_and_dbetteridge/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "glloyd_and_dbetteridge" +version = "0.1.0" diff --git a/glloyd_and_dbetteridge/Cargo.toml b/glloyd_and_dbetteridge/Cargo.toml new file mode 100644 index 0000000..cd2e808 --- /dev/null +++ b/glloyd_and_dbetteridge/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "glloyd_and_dbetteridge" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/glloyd_and_dbetteridge/src/main.rs b/glloyd_and_dbetteridge/src/main.rs new file mode 100644 index 0000000..7fcffe6 --- /dev/null +++ b/glloyd_and_dbetteridge/src/main.rs @@ -0,0 +1,84 @@ +fn main() { + println!("Hello, world!"); +} + +#[derive(PartialEq)] +enum GameState{ + eLoveAll, + e15Love, + e30Love, + eLove15 +} + +struct Game { + state: GameState +} + +impl Game { + pub(crate) fn point_for_player_two(&mut self) { + self.state = match self.state { + _ => GameState::eLove15, + } + } +} + +impl Game { + + fn new() -> Game { + Game { + state: GameState::eLoveAll + } + } + pub(crate) fn point_for_player_one(&mut self) { + if self.state == GameState::eLoveAll + { + self.state = GameState::e15Love; + } + else { + self.state = GameState::e30Love; + } + } + + pub(crate) fn print_score(&self) -> String { + match self.state { + GameState::eLoveAll => "love-all", + GameState::e15Love => "15-love", + GameState::e30Love => "30-love", + GameState::eLove15 => "love-15", + }.into() + } +} + +#[cfg(test)] +mod tests { + use crate::*; + + #[test] + fn a_new_game_is_love_all() { + let sut = Game::new(); + assert_eq!(sut.print_score(), "love-all"); + } + + + #[test] + fn if_player1_once_then_has_score_15_love() { + let mut sut = Game::new(); + sut.point_for_player_one(); + assert_eq!(sut.print_score(), "15-love"); + } + + #[test] + fn if_player1_scores_twice_then_has_score_30_love() { + let mut sut = Game::new(); + sut.point_for_player_one(); + sut.point_for_player_one(); + assert_eq!(sut.print_score(), "30-love"); + } + + #[test] + fn if_player2_once_then_has_score_love_15() { + let mut sut = Game::new(); + sut.point_for_player_two(); + assert_eq!(sut.print_score(), "love-15"); + } +} From 7f446f032c952a17e12953a6ad77b81ce5848b31 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Wed, 9 Jul 2025 20:30:04 +0100 Subject: [PATCH 02/15] wip --- glloyd_and_dbetteridge/src/main.rs | 162 +++++++++++++++++++++++------ 1 file changed, 133 insertions(+), 29 deletions(-) diff --git a/glloyd_and_dbetteridge/src/main.rs b/glloyd_and_dbetteridge/src/main.rs index 7fcffe6..908138a 100644 --- a/glloyd_and_dbetteridge/src/main.rs +++ b/glloyd_and_dbetteridge/src/main.rs @@ -1,51 +1,107 @@ +use std::fmt::Display; + fn main() { println!("Hello, world!"); } -#[derive(PartialEq)] -enum GameState{ - eLoveAll, - e15Love, - e30Love, - eLove15 +#[derive(PartialEq, Copy, Clone)] +enum PlayerScore { + Love, + Fifteen, + Thirty, + Forty, + Win, } -struct Game { - state: GameState +impl Display for PlayerScore { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let str = match self { + Self::Love => "love", + Self::Fifteen => "15", + Self::Thirty => "30", + Self::Forty => "40", + Self::Win => "player1 has won", + }; + write!(f, "{}", str) + } } -impl Game { - pub(crate) fn point_for_player_two(&mut self) { - self.state = match self.state { - _ => GameState::eLove15, +impl PlayerScore { + pub(crate) fn advance_score(self) -> Self { + match self { + Self::Love => Self::Fifteen, + Self::Fifteen => Self::Thirty, + Self::Thirty => Self::Forty, + Self::Forty => Self::Win, + Self::Win => Self::Win, } } } -impl Game { +#[derive(PartialEq, Copy, Clone)] +enum Game { + Deuce, + AdvantagePlayer1, + AdvantagePlayer2, + Scores(PlayerScore, PlayerScore), +} + +#[derive(PartialEq, Copy, Clone)] +enum Player { + One, + Two, +} +impl Game { fn new() -> Game { - Game { - state: GameState::eLoveAll + Game::Scores(PlayerScore::Love, PlayerScore::Love) + } + + pub(crate) fn advance_score(self, player: Player) -> Game { + match player { + Player::One => match self { + Game::Deuce => Game::AdvantagePlayer1, + Game::AdvantagePlayer1 => Game::AdvantagePlayer1, + Game::AdvantagePlayer2 => Game::AdvantagePlayer2, + Game::Scores(player1, player2) => match (player1, player2) { + (PlayerScore::Win, _) => Game::Scores(player1, player2), + (_, PlayerScore::Win) => Game::Scores(player1, player2), + (PlayerScore::Thirty, PlayerScore::Forty) => Game::Deuce, + _ => Game::Scores(player1.advance_score(), player2), + }, + }, + Player::Two => match self { + Game::Deuce => Game::AdvantagePlayer2, + Game::AdvantagePlayer1 => Game::AdvantagePlayer1, + Game::AdvantagePlayer2 => Game::AdvantagePlayer2, + Game::Scores(player1, player2) => match (player1, player2) { + (PlayerScore::Win, _) => Game::Scores(player1, player2), + (_, PlayerScore::Win) => Game::Scores(player1, player2), + (PlayerScore::Forty, PlayerScore::Thirty) => Game::Deuce, + _ => Game::Scores(player1, player2.advance_score()), + }, + }, } } + pub(crate) fn point_for_player_one(&mut self) { - if self.state == GameState::eLoveAll - { - self.state = GameState::e15Love; - } - else { - self.state = GameState::e30Love; - } + *self = self.advance_score(Player::One); + } + + pub(crate) fn point_for_player_two(&mut self) { + *self = self.advance_score(Player::Two); } pub(crate) fn print_score(&self) -> String { - match self.state { - GameState::eLoveAll => "love-all", - GameState::e15Love => "15-love", - GameState::e30Love => "30-love", - GameState::eLove15 => "love-15", - }.into() + match self { + Game::Deuce => format!("Deuce"), + Game::AdvantagePlayer1 => format!("Advantage player1"), + Game::AdvantagePlayer2 => format!("Advantage player2"), + Game::Scores(PlayerScore::Win, _) => format!("player1 has won"), + Game::Scores(_, PlayerScore::Win) => format!("player2 has won"), + Game::Scores(lhs, rhs) if lhs == rhs => format!("{}-all", lhs), + Game::Scores(lhs, rhs) => format!("{}-{}", lhs, rhs), + }.into() } } @@ -59,7 +115,6 @@ mod tests { assert_eq!(sut.print_score(), "love-all"); } - #[test] fn if_player1_once_then_has_score_15_love() { let mut sut = Game::new(); @@ -81,4 +136,53 @@ mod tests { sut.point_for_player_two(); assert_eq!(sut.print_score(), "love-15"); } + + #[test] + fn if_player1_scores_three_times_then_has_score_40_love() { + let mut sut = Game::new(); + sut.point_for_player_one(); + sut.point_for_player_one(); + sut.point_for_player_one(); + assert_eq!(sut.print_score(), "40-love"); + } + + #[test] + fn if_player1_scores_four_times_then_has_player1_has_won() { + let mut sut = Game::new(); + sut.point_for_player_one(); + sut.point_for_player_one(); + sut.point_for_player_one(); + sut.point_for_player_one(); + assert_eq!(sut.print_score(), "player1 has won"); + } + + #[test] + fn if_both_players_have_40_then_its_deuce() { + let mut sut = Game::new(); + sut.point_for_player_one(); + sut.point_for_player_one(); + sut.point_for_player_one(); + + sut.point_for_player_two(); + sut.point_for_player_two(); + sut.point_for_player_two(); + + assert_eq!(sut.print_score(), "Deuce"); + } + + #[test] + fn from_deuce_player1_can_take_the_advantage() { + let mut sut = Game::new(); + sut.point_for_player_one(); + sut.point_for_player_one(); + sut.point_for_player_one(); + + sut.point_for_player_two(); + sut.point_for_player_two(); + sut.point_for_player_two(); + + sut.point_for_player_one(); + + assert_eq!(sut.print_score(), "Advantage player1"); + } } From 27f3f28633ae13ca8ec6cbe376a7d5bbcedb2199 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Wed, 9 Jul 2025 20:30:53 +0100 Subject: [PATCH 03/15] wip --- glloyd_and_dbetteridge/src/main.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/glloyd_and_dbetteridge/src/main.rs b/glloyd_and_dbetteridge/src/main.rs index 908138a..3a77a20 100644 --- a/glloyd_and_dbetteridge/src/main.rs +++ b/glloyd_and_dbetteridge/src/main.rs @@ -94,11 +94,11 @@ impl Game { pub(crate) fn print_score(&self) -> String { match self { - Game::Deuce => format!("Deuce"), - Game::AdvantagePlayer1 => format!("Advantage player1"), - Game::AdvantagePlayer2 => format!("Advantage player2"), - Game::Scores(PlayerScore::Win, _) => format!("player1 has won"), - Game::Scores(_, PlayerScore::Win) => format!("player2 has won"), + Game::Deuce => "Deuce".to_string(), + Game::AdvantagePlayer1 => "Advantage player1".to_string(), + Game::AdvantagePlayer2 => "Advantage player2".to_string(), + Game::Scores(PlayerScore::Win, _) => "player1 has won".to_string(), + Game::Scores(_, PlayerScore::Win) => "player2 has won".to_string(), Game::Scores(lhs, rhs) if lhs == rhs => format!("{}-all", lhs), Game::Scores(lhs, rhs) => format!("{}-{}", lhs, rhs), }.into() From 6aa3aacc0ebe45843338bd6e99a32959a9db18e8 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Wed, 9 Jul 2025 20:43:22 +0100 Subject: [PATCH 04/15] wip --- glloyd_and_dbetteridge/Cargo.lock | 263 +++++++++++++++++++++++++++++ glloyd_and_dbetteridge/Cargo.toml | 1 + glloyd_and_dbetteridge/src/main.rs | 103 +++-------- 3 files changed, 292 insertions(+), 75 deletions(-) diff --git a/glloyd_and_dbetteridge/Cargo.lock b/glloyd_and_dbetteridge/Cargo.lock index 047eb40..727ddc1 100644 --- a/glloyd_and_dbetteridge/Cargo.lock +++ b/glloyd_and_dbetteridge/Cargo.lock @@ -2,6 +2,269 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "glloyd_and_dbetteridge" version = "0.1.0" +dependencies = [ + "rstest", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "rstest" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fc39292f8613e913f7df8fa892b8944ceb47c247b78e1b1ae2f09e019be789d" +dependencies = [ + "futures-timer", + "futures-util", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f168d99749d307be9de54d23fd226628d99768225ef08f6ffb52e0182a27746" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn", + "unicode-ident", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "slab" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "winnow" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +dependencies = [ + "memchr", +] diff --git a/glloyd_and_dbetteridge/Cargo.toml b/glloyd_and_dbetteridge/Cargo.toml index cd2e808..e9e5778 100644 --- a/glloyd_and_dbetteridge/Cargo.toml +++ b/glloyd_and_dbetteridge/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2024" [dependencies] +rstest = "0.25.0" diff --git a/glloyd_and_dbetteridge/src/main.rs b/glloyd_and_dbetteridge/src/main.rs index 3a77a20..942d63d 100644 --- a/glloyd_and_dbetteridge/src/main.rs +++ b/glloyd_and_dbetteridge/src/main.rs @@ -101,7 +101,8 @@ impl Game { Game::Scores(_, PlayerScore::Win) => "player2 has won".to_string(), Game::Scores(lhs, rhs) if lhs == rhs => format!("{}-all", lhs), Game::Scores(lhs, rhs) => format!("{}-{}", lhs, rhs), - }.into() + } + .into() } } @@ -109,80 +110,32 @@ impl Game { mod tests { use crate::*; - #[test] - fn a_new_game_is_love_all() { - let sut = Game::new(); - assert_eq!(sut.print_score(), "love-all"); - } - - #[test] - fn if_player1_once_then_has_score_15_love() { - let mut sut = Game::new(); - sut.point_for_player_one(); - assert_eq!(sut.print_score(), "15-love"); - } - - #[test] - fn if_player1_scores_twice_then_has_score_30_love() { - let mut sut = Game::new(); - sut.point_for_player_one(); - sut.point_for_player_one(); - assert_eq!(sut.print_score(), "30-love"); - } - - #[test] - fn if_player2_once_then_has_score_love_15() { - let mut sut = Game::new(); - sut.point_for_player_two(); - assert_eq!(sut.print_score(), "love-15"); - } - - #[test] - fn if_player1_scores_three_times_then_has_score_40_love() { - let mut sut = Game::new(); - sut.point_for_player_one(); - sut.point_for_player_one(); - sut.point_for_player_one(); - assert_eq!(sut.print_score(), "40-love"); - } - - #[test] - fn if_player1_scores_four_times_then_has_player1_has_won() { - let mut sut = Game::new(); - sut.point_for_player_one(); - sut.point_for_player_one(); - sut.point_for_player_one(); - sut.point_for_player_one(); - assert_eq!(sut.print_score(), "player1 has won"); - } - - #[test] - fn if_both_players_have_40_then_its_deuce() { - let mut sut = Game::new(); - sut.point_for_player_one(); - sut.point_for_player_one(); - sut.point_for_player_one(); - - sut.point_for_player_two(); - sut.point_for_player_two(); - sut.point_for_player_two(); - - assert_eq!(sut.print_score(), "Deuce"); - } - - #[test] - fn from_deuce_player1_can_take_the_advantage() { - let mut sut = Game::new(); - sut.point_for_player_one(); - sut.point_for_player_one(); - sut.point_for_player_one(); - - sut.point_for_player_two(); - sut.point_for_player_two(); - sut.point_for_player_two(); - - sut.point_for_player_one(); + use rstest::rstest; + + #[rstest] + #[case(vec!(0,0), "love-all")] + #[case(vec!(1,0), "15-love")] + #[case(vec!(2,0), "30-love")] + #[case(vec!(0,1), "love-15")] + #[case(vec!(3,0), "40-love")] + #[case(vec!(4,0), "player1 has won")] + #[case(vec!(3,3), "Deuce")] + #[case(vec!(3,3,1), "Advantage player1")] + fn test_tennis_scoring(#[case] sequence: Vec, #[case] expected: &str) { + let mut game = Game::new(); + + for (i, &n) in sequence.iter().enumerate() { + if i % 2 == 0 { + for _ in 0..n { + game.point_for_player_one(); + } + } else { + for _ in 0..n { + game.point_for_player_two(); + } + } + } - assert_eq!(sut.print_score(), "Advantage player1"); + assert_eq!(game.print_score(), expected); } } From 49ed9fb45e2b0769b6b31ecb5d804b100019fbdc Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Wed, 9 Jul 2025 20:53:16 +0100 Subject: [PATCH 05/15] wip --- glloyd_and_dbetteridge/src/main.rs | 41 ++++++++++++++---------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/glloyd_and_dbetteridge/src/main.rs b/glloyd_and_dbetteridge/src/main.rs index 942d63d..ad7a010 100644 --- a/glloyd_and_dbetteridge/src/main.rs +++ b/glloyd_and_dbetteridge/src/main.rs @@ -10,7 +10,6 @@ enum PlayerScore { Fifteen, Thirty, Forty, - Win, } impl Display for PlayerScore { @@ -20,7 +19,6 @@ impl Display for PlayerScore { Self::Fifteen => "15", Self::Thirty => "30", Self::Forty => "40", - Self::Win => "player1 has won", }; write!(f, "{}", str) } @@ -32,8 +30,7 @@ impl PlayerScore { Self::Love => Self::Fifteen, Self::Fifteen => Self::Thirty, Self::Thirty => Self::Forty, - Self::Forty => Self::Win, - Self::Win => Self::Win, + Self::Forty => Self::Forty, } } } @@ -43,6 +40,8 @@ enum Game { Deuce, AdvantagePlayer1, AdvantagePlayer2, + Player1Win, + Player2Win, Scores(PlayerScore, PlayerScore), } @@ -61,25 +60,21 @@ impl Game { match player { Player::One => match self { Game::Deuce => Game::AdvantagePlayer1, - Game::AdvantagePlayer1 => Game::AdvantagePlayer1, - Game::AdvantagePlayer2 => Game::AdvantagePlayer2, - Game::Scores(player1, player2) => match (player1, player2) { - (PlayerScore::Win, _) => Game::Scores(player1, player2), - (_, PlayerScore::Win) => Game::Scores(player1, player2), - (PlayerScore::Thirty, PlayerScore::Forty) => Game::Deuce, - _ => Game::Scores(player1.advance_score(), player2), - }, + Game::AdvantagePlayer1 => Game::Player1Win, + Game::AdvantagePlayer2 => Game::Deuce, + Game::Scores(PlayerScore::Thirty, PlayerScore::Forty) => Game::Deuce, + Game::Scores(PlayerScore::Forty, _) => Game::Player1Win, + Game::Scores(player1, player2) => Game::Scores(player1.advance_score(), player2), + x => x, }, Player::Two => match self { Game::Deuce => Game::AdvantagePlayer2, - Game::AdvantagePlayer1 => Game::AdvantagePlayer1, - Game::AdvantagePlayer2 => Game::AdvantagePlayer2, - Game::Scores(player1, player2) => match (player1, player2) { - (PlayerScore::Win, _) => Game::Scores(player1, player2), - (_, PlayerScore::Win) => Game::Scores(player1, player2), - (PlayerScore::Forty, PlayerScore::Thirty) => Game::Deuce, - _ => Game::Scores(player1, player2.advance_score()), - }, + Game::AdvantagePlayer1 => Game::Deuce, + Game::AdvantagePlayer2 => Game::Player2Win, + Game::Scores(PlayerScore::Forty, PlayerScore::Thirty) => Game::Deuce, + Game::Scores(_, PlayerScore::Forty) => Game::Player2Win, + Game::Scores(player1, player2) => Game::Scores(player1, player2.advance_score()), + x => x, }, } } @@ -97,8 +92,8 @@ impl Game { Game::Deuce => "Deuce".to_string(), Game::AdvantagePlayer1 => "Advantage player1".to_string(), Game::AdvantagePlayer2 => "Advantage player2".to_string(), - Game::Scores(PlayerScore::Win, _) => "player1 has won".to_string(), - Game::Scores(_, PlayerScore::Win) => "player2 has won".to_string(), + Game::Player1Win => "player1 has won".to_string(), + Game::Player2Win => "player2 has won".to_string(), Game::Scores(lhs, rhs) if lhs == rhs => format!("{}-all", lhs), Game::Scores(lhs, rhs) => format!("{}-{}", lhs, rhs), } @@ -121,6 +116,8 @@ mod tests { #[case(vec!(4,0), "player1 has won")] #[case(vec!(3,3), "Deuce")] #[case(vec!(3,3,1), "Advantage player1")] + #[case(vec!(3,3,2), "player1 has won")] + #[case(vec!(3,3,1,1), "Deuce")] fn test_tennis_scoring(#[case] sequence: Vec, #[case] expected: &str) { let mut game = Game::new(); From 525661e284f5cf4d58838ecdeca8c946996fcfb5 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Wed, 9 Jul 2025 21:00:14 +0100 Subject: [PATCH 06/15] wip --- glloyd_and_dbetteridge/src/main.rs | 40 ++++++++++++++++-------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/glloyd_and_dbetteridge/src/main.rs b/glloyd_and_dbetteridge/src/main.rs index ad7a010..691b5a4 100644 --- a/glloyd_and_dbetteridge/src/main.rs +++ b/glloyd_and_dbetteridge/src/main.rs @@ -57,25 +57,27 @@ impl Game { } pub(crate) fn advance_score(self, player: Player) -> Game { - match player { - Player::One => match self { - Game::Deuce => Game::AdvantagePlayer1, - Game::AdvantagePlayer1 => Game::Player1Win, - Game::AdvantagePlayer2 => Game::Deuce, - Game::Scores(PlayerScore::Thirty, PlayerScore::Forty) => Game::Deuce, - Game::Scores(PlayerScore::Forty, _) => Game::Player1Win, - Game::Scores(player1, player2) => Game::Scores(player1.advance_score(), player2), - x => x, - }, - Player::Two => match self { - Game::Deuce => Game::AdvantagePlayer2, - Game::AdvantagePlayer1 => Game::Deuce, - Game::AdvantagePlayer2 => Game::Player2Win, - Game::Scores(PlayerScore::Forty, PlayerScore::Thirty) => Game::Deuce, - Game::Scores(_, PlayerScore::Forty) => Game::Player2Win, - Game::Scores(player1, player2) => Game::Scores(player1, player2.advance_score()), - x => x, - }, + match (player, self) { + (Player::One, Game::Deuce) => Game::AdvantagePlayer1, + (Player::Two, Game::Deuce) => Game::AdvantagePlayer2, + + (Player::One, Game::AdvantagePlayer2) => Game::Deuce, + (Player::Two, Game::AdvantagePlayer1) => Game::Deuce, + (Player::One, Game::Scores(PlayerScore::Thirty, PlayerScore::Forty)) => Game::Deuce, + (Player::Two, Game::Scores(PlayerScore::Forty, PlayerScore::Thirty)) => Game::Deuce, + + (Player::One, Game::AdvantagePlayer1) => Game::Player1Win, + (Player::Two, Game::AdvantagePlayer2) => Game::Player2Win, + (Player::One, Game::Scores(PlayerScore::Forty, _)) => Game::Player1Win, + (Player::Two, Game::Scores(_, PlayerScore::Forty)) => Game::Player2Win, + + (Player::One, Game::Scores(player1, player2)) => { + Game::Scores(player1.advance_score(), player2) + } + (Player::Two, Game::Scores(player1, player2)) => { + Game::Scores(player1, player2.advance_score()) + } + (_, x) => x, } } From 2ce3184461f1a5a0999146ecf0c4407fdd31e3e4 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Wed, 9 Jul 2025 21:06:05 +0100 Subject: [PATCH 07/15] wip --- glloyd_and_dbetteridge/Cargo.lock | 14 +-- glloyd_and_dbetteridge/Cargo.toml | 5 +- glloyd_and_dbetteridge/src/lib.rs | 136 +++++++++++++++++++++++++++ glloyd_and_dbetteridge/src/main.rs | 146 ++--------------------------- 4 files changed, 156 insertions(+), 145 deletions(-) create mode 100644 glloyd_and_dbetteridge/src/lib.rs diff --git a/glloyd_and_dbetteridge/Cargo.lock b/glloyd_and_dbetteridge/Cargo.lock index 727ddc1..113946d 100644 --- a/glloyd_and_dbetteridge/Cargo.lock +++ b/glloyd_and_dbetteridge/Cargo.lock @@ -66,13 +66,6 @@ dependencies = [ "slab", ] -[[package]] -name = "glloyd_and_dbetteridge" -version = "0.1.0" -dependencies = [ - "rstest", -] - [[package]] name = "glob" version = "0.3.2" @@ -237,6 +230,13 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tennis" +version = "0.1.0" +dependencies = [ + "rstest", +] + [[package]] name = "toml_datetime" version = "0.6.11" diff --git a/glloyd_and_dbetteridge/Cargo.toml b/glloyd_and_dbetteridge/Cargo.toml index e9e5778..e446a79 100644 --- a/glloyd_and_dbetteridge/Cargo.toml +++ b/glloyd_and_dbetteridge/Cargo.toml @@ -1,7 +1,10 @@ [package] -name = "glloyd_and_dbetteridge" +name = "tennis" version = "0.1.0" edition = "2024" +[lib] +name = "tennis" + [dependencies] rstest = "0.25.0" diff --git a/glloyd_and_dbetteridge/src/lib.rs b/glloyd_and_dbetteridge/src/lib.rs new file mode 100644 index 0000000..66bbf8d --- /dev/null +++ b/glloyd_and_dbetteridge/src/lib.rs @@ -0,0 +1,136 @@ +use std::fmt::Display; + +#[derive(PartialEq, Copy, Clone)] +enum PlayerScore { + Love, + Fifteen, + Thirty, + Forty, +} + +impl Display for PlayerScore { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let str = match self { + Self::Love => "love", + Self::Fifteen => "15", + Self::Thirty => "30", + Self::Forty => "40", + }; + write!(f, "{}", str) + } +} + +impl PlayerScore { + fn advance_score(self) -> Self { + match self { + Self::Love => Self::Fifteen, + Self::Fifteen => Self::Thirty, + Self::Thirty => Self::Forty, + Self::Forty => Self::Forty, + } + } +} + +#[derive(PartialEq, Copy, Clone)] +pub enum Game { + Deuce, + AdvantagePlayer1, + AdvantagePlayer2, + Player1Win, + Player2Win, + Scores(PlayerScore, PlayerScore), +} + +#[derive(PartialEq, Copy, Clone)] +pub enum Player { + One, + Two, +} + +impl Game { + pub fn new() -> Game { + Game::Scores(PlayerScore::Love, PlayerScore::Love) + } + + pub fn advance_score(self, player: Player) -> Game { + match (player, self) { + (Player::One, Game::Deuce) => Game::AdvantagePlayer1, + (Player::Two, Game::Deuce) => Game::AdvantagePlayer2, + + (Player::One, Game::AdvantagePlayer2) => Game::Deuce, + (Player::Two, Game::AdvantagePlayer1) => Game::Deuce, + (Player::One, Game::Scores(PlayerScore::Thirty, PlayerScore::Forty)) => Game::Deuce, + (Player::Two, Game::Scores(PlayerScore::Forty, PlayerScore::Thirty)) => Game::Deuce, + + (Player::One, Game::AdvantagePlayer1) => Game::Player1Win, + (Player::Two, Game::AdvantagePlayer2) => Game::Player2Win, + (Player::One, Game::Scores(PlayerScore::Forty, _)) => Game::Player1Win, + (Player::Two, Game::Scores(_, PlayerScore::Forty)) => Game::Player2Win, + + (Player::One, Game::Scores(player1, player2)) => { + Game::Scores(player1.advance_score(), player2) + } + (Player::Two, Game::Scores(player1, player2)) => { + Game::Scores(player1, player2.advance_score()) + } + (_, x) => x, + } + } + + pub fn point_for_player_one(&mut self) { + *self = self.advance_score(Player::One); + } + + pub fn point_for_player_two(&mut self) { + *self = self.advance_score(Player::Two); + } + + pub fn print_score(&self) -> String { + match self { + Game::Deuce => "Deuce".to_string(), + Game::AdvantagePlayer1 => "Advantage player1".to_string(), + Game::AdvantagePlayer2 => "Advantage player2".to_string(), + Game::Player1Win => "player1 has won".to_string(), + Game::Player2Win => "player2 has won".to_string(), + Game::Scores(lhs, rhs) if lhs == rhs => format!("{}-all", lhs), + Game::Scores(lhs, rhs) => format!("{}-{}", lhs, rhs), + } + .into() + } +} + +#[cfg(test)] +mod tests { + use crate::*; + + use rstest::rstest; + + #[rstest] + #[case(vec!(0,0), "love-all")] + #[case(vec!(1,0), "15-love")] + #[case(vec!(2,0), "30-love")] + #[case(vec!(0,1), "love-15")] + #[case(vec!(3,0), "40-love")] + #[case(vec!(4,0), "player1 has won")] + #[case(vec!(3,3), "Deuce")] + #[case(vec!(3,3,1), "Advantage player1")] + #[case(vec!(3,3,2), "player1 has won")] + #[case(vec!(3,3,1,1), "Deuce")] + fn test_tennis_scoring(#[case] sequence: Vec, #[case] expected: &str) { + let mut game = Game::new(); + + for (i, &n) in sequence.iter().enumerate() { + if i % 2 == 0 { + for _ in 0..n { + game.point_for_player_one(); + } + } else { + for _ in 0..n { + game.point_for_player_two(); + } + } + } + + assert_eq!(game.print_score(), expected); + } +} \ No newline at end of file diff --git a/glloyd_and_dbetteridge/src/main.rs b/glloyd_and_dbetteridge/src/main.rs index 691b5a4..09e315c 100644 --- a/glloyd_and_dbetteridge/src/main.rs +++ b/glloyd_and_dbetteridge/src/main.rs @@ -1,140 +1,12 @@ -use std::fmt::Display; +use tennis::Game; fn main() { - println!("Hello, world!"); -} - -#[derive(PartialEq, Copy, Clone)] -enum PlayerScore { - Love, - Fifteen, - Thirty, - Forty, -} - -impl Display for PlayerScore { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let str = match self { - Self::Love => "love", - Self::Fifteen => "15", - Self::Thirty => "30", - Self::Forty => "40", - }; - write!(f, "{}", str) - } -} - -impl PlayerScore { - pub(crate) fn advance_score(self) -> Self { - match self { - Self::Love => Self::Fifteen, - Self::Fifteen => Self::Thirty, - Self::Thirty => Self::Forty, - Self::Forty => Self::Forty, - } - } -} - -#[derive(PartialEq, Copy, Clone)] -enum Game { - Deuce, - AdvantagePlayer1, - AdvantagePlayer2, - Player1Win, - Player2Win, - Scores(PlayerScore, PlayerScore), -} - -#[derive(PartialEq, Copy, Clone)] -enum Player { - One, - Two, -} - -impl Game { - fn new() -> Game { - Game::Scores(PlayerScore::Love, PlayerScore::Love) - } - - pub(crate) fn advance_score(self, player: Player) -> Game { - match (player, self) { - (Player::One, Game::Deuce) => Game::AdvantagePlayer1, - (Player::Two, Game::Deuce) => Game::AdvantagePlayer2, - - (Player::One, Game::AdvantagePlayer2) => Game::Deuce, - (Player::Two, Game::AdvantagePlayer1) => Game::Deuce, - (Player::One, Game::Scores(PlayerScore::Thirty, PlayerScore::Forty)) => Game::Deuce, - (Player::Two, Game::Scores(PlayerScore::Forty, PlayerScore::Thirty)) => Game::Deuce, - - (Player::One, Game::AdvantagePlayer1) => Game::Player1Win, - (Player::Two, Game::AdvantagePlayer2) => Game::Player2Win, - (Player::One, Game::Scores(PlayerScore::Forty, _)) => Game::Player1Win, - (Player::Two, Game::Scores(_, PlayerScore::Forty)) => Game::Player2Win, - - (Player::One, Game::Scores(player1, player2)) => { - Game::Scores(player1.advance_score(), player2) - } - (Player::Two, Game::Scores(player1, player2)) => { - Game::Scores(player1, player2.advance_score()) - } - (_, x) => x, - } - } - - pub(crate) fn point_for_player_one(&mut self) { - *self = self.advance_score(Player::One); - } - - pub(crate) fn point_for_player_two(&mut self) { - *self = self.advance_score(Player::Two); - } - - pub(crate) fn print_score(&self) -> String { - match self { - Game::Deuce => "Deuce".to_string(), - Game::AdvantagePlayer1 => "Advantage player1".to_string(), - Game::AdvantagePlayer2 => "Advantage player2".to_string(), - Game::Player1Win => "player1 has won".to_string(), - Game::Player2Win => "player2 has won".to_string(), - Game::Scores(lhs, rhs) if lhs == rhs => format!("{}-all", lhs), - Game::Scores(lhs, rhs) => format!("{}-{}", lhs, rhs), - } - .into() - } -} - -#[cfg(test)] -mod tests { - use crate::*; - - use rstest::rstest; - - #[rstest] - #[case(vec!(0,0), "love-all")] - #[case(vec!(1,0), "15-love")] - #[case(vec!(2,0), "30-love")] - #[case(vec!(0,1), "love-15")] - #[case(vec!(3,0), "40-love")] - #[case(vec!(4,0), "player1 has won")] - #[case(vec!(3,3), "Deuce")] - #[case(vec!(3,3,1), "Advantage player1")] - #[case(vec!(3,3,2), "player1 has won")] - #[case(vec!(3,3,1,1), "Deuce")] - fn test_tennis_scoring(#[case] sequence: Vec, #[case] expected: &str) { - let mut game = Game::new(); - - for (i, &n) in sequence.iter().enumerate() { - if i % 2 == 0 { - for _ in 0..n { - game.point_for_player_one(); - } - } else { - for _ in 0..n { - game.point_for_player_two(); - } - } - } - - assert_eq!(game.print_score(), expected); - } + let mut game = Game::new(); + println!("Starting game: {}", game.print_score()); + + game.point_for_player_one(); + println!("After player 1 scores: {}", game.print_score()); + + game.point_for_player_two(); + println!("After player 2 scores: {}", game.print_score()); } From 2df58f0a2318b28699698f60f2f71cbe34223472 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Wed, 9 Jul 2025 21:07:39 +0100 Subject: [PATCH 08/15] wip --- glloyd_and_dbetteridge/src/lib.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/glloyd_and_dbetteridge/src/lib.rs b/glloyd_and_dbetteridge/src/lib.rs index 66bbf8d..d3ed09b 100644 --- a/glloyd_and_dbetteridge/src/lib.rs +++ b/glloyd_and_dbetteridge/src/lib.rs @@ -54,14 +54,14 @@ impl Game { pub fn advance_score(self, player: Player) -> Game { match (player, self) { - (Player::One, Game::Deuce) => Game::AdvantagePlayer1, - (Player::Two, Game::Deuce) => Game::AdvantagePlayer2, - (Player::One, Game::AdvantagePlayer2) => Game::Deuce, (Player::Two, Game::AdvantagePlayer1) => Game::Deuce, (Player::One, Game::Scores(PlayerScore::Thirty, PlayerScore::Forty)) => Game::Deuce, (Player::Two, Game::Scores(PlayerScore::Forty, PlayerScore::Thirty)) => Game::Deuce, + (Player::One, Game::Deuce) => Game::AdvantagePlayer1, + (Player::Two, Game::Deuce) => Game::AdvantagePlayer2, + (Player::One, Game::AdvantagePlayer1) => Game::Player1Win, (Player::Two, Game::AdvantagePlayer2) => Game::Player2Win, (Player::One, Game::Scores(PlayerScore::Forty, _)) => Game::Player1Win, @@ -95,7 +95,6 @@ impl Game { Game::Scores(lhs, rhs) if lhs == rhs => format!("{}-all", lhs), Game::Scores(lhs, rhs) => format!("{}-{}", lhs, rhs), } - .into() } } @@ -133,4 +132,4 @@ mod tests { assert_eq!(game.print_score(), expected); } -} \ No newline at end of file +} From 0b1582d538e83f4d4a4d9094fad9c4830e33d149 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Wed, 9 Jul 2025 21:09:22 +0100 Subject: [PATCH 09/15] wip --- glloyd_and_dbetteridge/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glloyd_and_dbetteridge/src/lib.rs b/glloyd_and_dbetteridge/src/lib.rs index d3ed09b..d72ab74 100644 --- a/glloyd_and_dbetteridge/src/lib.rs +++ b/glloyd_and_dbetteridge/src/lib.rs @@ -1,7 +1,7 @@ use std::fmt::Display; #[derive(PartialEq, Copy, Clone)] -enum PlayerScore { +pub enum PlayerScore { Love, Fifteen, Thirty, From 43370a665c298d2a00cffd3719fa9fbb24d5ba0f Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Wed, 9 Jul 2025 21:25:12 +0100 Subject: [PATCH 10/15] wip --- glloyd_and_dbetteridge/src/lib.rs | 48 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/glloyd_and_dbetteridge/src/lib.rs b/glloyd_and_dbetteridge/src/lib.rs index d72ab74..5631ab9 100644 --- a/glloyd_and_dbetteridge/src/lib.rs +++ b/glloyd_and_dbetteridge/src/lib.rs @@ -48,30 +48,30 @@ pub enum Player { } impl Game { - pub fn new() -> Game { - Game::Scores(PlayerScore::Love, PlayerScore::Love) + pub fn new() -> Self { + Self::Scores(PlayerScore::Love, PlayerScore::Love) } - pub fn advance_score(self, player: Player) -> Game { + pub fn advance_score(self, player: Player) -> Self { match (player, self) { - (Player::One, Game::AdvantagePlayer2) => Game::Deuce, - (Player::Two, Game::AdvantagePlayer1) => Game::Deuce, - (Player::One, Game::Scores(PlayerScore::Thirty, PlayerScore::Forty)) => Game::Deuce, - (Player::Two, Game::Scores(PlayerScore::Forty, PlayerScore::Thirty)) => Game::Deuce, + (Player::One, Self::AdvantagePlayer2) => Self::Deuce, + (Player::Two, Self::AdvantagePlayer1) => Self::Deuce, + (Player::One, Self::Scores(PlayerScore::Thirty, PlayerScore::Forty)) => Self::Deuce, + (Player::Two, Self::Scores(PlayerScore::Forty, PlayerScore::Thirty)) => Self::Deuce, - (Player::One, Game::Deuce) => Game::AdvantagePlayer1, - (Player::Two, Game::Deuce) => Game::AdvantagePlayer2, + (Player::One, Self::Deuce) => Self::AdvantagePlayer1, + (Player::Two, Self::Deuce) => Self::AdvantagePlayer2, - (Player::One, Game::AdvantagePlayer1) => Game::Player1Win, - (Player::Two, Game::AdvantagePlayer2) => Game::Player2Win, - (Player::One, Game::Scores(PlayerScore::Forty, _)) => Game::Player1Win, - (Player::Two, Game::Scores(_, PlayerScore::Forty)) => Game::Player2Win, + (Player::One, Self::AdvantagePlayer1) => Self::Player1Win, + (Player::Two, Self::AdvantagePlayer2) => Self::Player2Win, + (Player::One, Self::Scores(PlayerScore::Forty, _)) => Self::Player1Win, + (Player::Two, Self::Scores(_, PlayerScore::Forty)) => Self::Player2Win, - (Player::One, Game::Scores(player1, player2)) => { - Game::Scores(player1.advance_score(), player2) + (Player::One, Self::Scores(player1, player2)) => { + Self::Scores(player1.advance_score(), player2) } - (Player::Two, Game::Scores(player1, player2)) => { - Game::Scores(player1, player2.advance_score()) + (Player::Two, Self::Scores(player1, player2)) => { + Self::Scores(player1, player2.advance_score()) } (_, x) => x, } @@ -87,13 +87,13 @@ impl Game { pub fn print_score(&self) -> String { match self { - Game::Deuce => "Deuce".to_string(), - Game::AdvantagePlayer1 => "Advantage player1".to_string(), - Game::AdvantagePlayer2 => "Advantage player2".to_string(), - Game::Player1Win => "player1 has won".to_string(), - Game::Player2Win => "player2 has won".to_string(), - Game::Scores(lhs, rhs) if lhs == rhs => format!("{}-all", lhs), - Game::Scores(lhs, rhs) => format!("{}-{}", lhs, rhs), + Self::Deuce => "Deuce".to_string(), + Self::AdvantagePlayer1 => "Advantage player1".to_string(), + Self::AdvantagePlayer2 => "Advantage player2".to_string(), + Self::Player1Win => "player1 has won".to_string(), + Self::Player2Win => "player2 has won".to_string(), + Self::Scores(lhs, rhs) if lhs == rhs => format!("{}-all", lhs), + Self::Scores(lhs, rhs) => format!("{}-{}", lhs, rhs), } } } From dc836282ce9717203eaf816001df050a57c19ab0 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Thu, 10 Jul 2025 00:20:05 +0100 Subject: [PATCH 11/15] wip --- glloyd_and_dbetteridge/src/lib.rs | 41 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/glloyd_and_dbetteridge/src/lib.rs b/glloyd_and_dbetteridge/src/lib.rs index 5631ab9..9205f21 100644 --- a/glloyd_and_dbetteridge/src/lib.rs +++ b/glloyd_and_dbetteridge/src/lib.rs @@ -34,10 +34,8 @@ impl PlayerScore { #[derive(PartialEq, Copy, Clone)] pub enum Game { Deuce, - AdvantagePlayer1, - AdvantagePlayer2, - Player1Win, - Player2Win, + Advantage(Player), + Win(Player), Scores(PlayerScore, PlayerScore), } @@ -47,6 +45,16 @@ pub enum Player { Two, } +impl Display for Player { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let str = match self { + Player::One => "Player 1", + Player::Two => "Player 2", + }; + write!(f, "{}", str) + } +} + impl Game { pub fn new() -> Self { Self::Scores(PlayerScore::Love, PlayerScore::Love) @@ -54,18 +62,15 @@ impl Game { pub fn advance_score(self, player: Player) -> Self { match (player, self) { - (Player::One, Self::AdvantagePlayer2) => Self::Deuce, - (Player::Two, Self::AdvantagePlayer1) => Self::Deuce, + (x, Self::Advantage(y)) if x != y => Self::Deuce, (Player::One, Self::Scores(PlayerScore::Thirty, PlayerScore::Forty)) => Self::Deuce, (Player::Two, Self::Scores(PlayerScore::Forty, PlayerScore::Thirty)) => Self::Deuce, - (Player::One, Self::Deuce) => Self::AdvantagePlayer1, - (Player::Two, Self::Deuce) => Self::AdvantagePlayer2, + (x, Self::Deuce) => Self::Advantage(x), - (Player::One, Self::AdvantagePlayer1) => Self::Player1Win, - (Player::Two, Self::AdvantagePlayer2) => Self::Player2Win, - (Player::One, Self::Scores(PlayerScore::Forty, _)) => Self::Player1Win, - (Player::Two, Self::Scores(_, PlayerScore::Forty)) => Self::Player2Win, + (x, Self::Advantage(y)) if x == y => Self::Win(x), + (Player::One, Self::Scores(PlayerScore::Forty, _)) => Self::Win(Player::One), + (Player::Two, Self::Scores(_, PlayerScore::Forty)) => Self::Win(Player::Two), (Player::One, Self::Scores(player1, player2)) => { Self::Scores(player1.advance_score(), player2) @@ -88,10 +93,8 @@ impl Game { pub fn print_score(&self) -> String { match self { Self::Deuce => "Deuce".to_string(), - Self::AdvantagePlayer1 => "Advantage player1".to_string(), - Self::AdvantagePlayer2 => "Advantage player2".to_string(), - Self::Player1Win => "player1 has won".to_string(), - Self::Player2Win => "player2 has won".to_string(), + Self::Advantage(x) => format!("Advantage {}", x), + Self::Win(x) => format!("{} has won", x), Self::Scores(lhs, rhs) if lhs == rhs => format!("{}-all", lhs), Self::Scores(lhs, rhs) => format!("{}-{}", lhs, rhs), } @@ -110,10 +113,10 @@ mod tests { #[case(vec!(2,0), "30-love")] #[case(vec!(0,1), "love-15")] #[case(vec!(3,0), "40-love")] - #[case(vec!(4,0), "player1 has won")] + #[case(vec!(4,0), "Player 1 has won")] #[case(vec!(3,3), "Deuce")] - #[case(vec!(3,3,1), "Advantage player1")] - #[case(vec!(3,3,2), "player1 has won")] + #[case(vec!(3,3,1), "Advantage Player 1")] + #[case(vec!(3,3,2), "Player 1 has won")] #[case(vec!(3,3,1,1), "Deuce")] fn test_tennis_scoring(#[case] sequence: Vec, #[case] expected: &str) { let mut game = Game::new(); From 49affc10a2ff69a1b69d7c3144479e780f056ae9 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Thu, 10 Jul 2025 00:28:18 +0100 Subject: [PATCH 12/15] wip --- glloyd_and_dbetteridge/src/lib.rs | 51 +++++++++++++++--------------- glloyd_and_dbetteridge/src/main.rs | 12 +++---- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/glloyd_and_dbetteridge/src/lib.rs b/glloyd_and_dbetteridge/src/lib.rs index 9205f21..0370079 100644 --- a/glloyd_and_dbetteridge/src/lib.rs +++ b/glloyd_and_dbetteridge/src/lib.rs @@ -55,9 +55,28 @@ impl Display for Player { } } +impl Default for Game { + fn default() -> Self { + Self::Scores(PlayerScore::Love, PlayerScore::Love) + } +} + +impl Display for Game { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let score_text = match self { + Self::Deuce => "Deuce", + Self::Advantage(player) => return write!(f, "Advantage {}", player), + Self::Win(player) => return write!(f, "{} has won", player), + Self::Scores(lhs, rhs) if lhs == rhs => return write!(f, "{}-all", lhs), + Self::Scores(lhs, rhs) => return write!(f, "{}-{}", lhs, rhs), + }; + write!(f, "{}", score_text) + } +} + impl Game { pub fn new() -> Self { - Self::Scores(PlayerScore::Love, PlayerScore::Love) + Self::default() } pub fn advance_score(self, player: Player) -> Self { @@ -82,23 +101,10 @@ impl Game { } } - pub fn point_for_player_one(&mut self) { - *self = self.advance_score(Player::One); - } - - pub fn point_for_player_two(&mut self) { - *self = self.advance_score(Player::Two); + pub fn score_point(&mut self, player: Player) { + *self = self.advance_score(player); } - pub fn print_score(&self) -> String { - match self { - Self::Deuce => "Deuce".to_string(), - Self::Advantage(x) => format!("Advantage {}", x), - Self::Win(x) => format!("{} has won", x), - Self::Scores(lhs, rhs) if lhs == rhs => format!("{}-all", lhs), - Self::Scores(lhs, rhs) => format!("{}-{}", lhs, rhs), - } - } } #[cfg(test)] @@ -122,17 +128,12 @@ mod tests { let mut game = Game::new(); for (i, &n) in sequence.iter().enumerate() { - if i % 2 == 0 { - for _ in 0..n { - game.point_for_player_one(); - } - } else { - for _ in 0..n { - game.point_for_player_two(); - } + let player = if i % 2 == 0 { Player::One } else { Player::Two }; + for _ in 0..n { + game.score_point(player); } } - assert_eq!(game.print_score(), expected); + assert_eq!(game.to_string(), expected); } } diff --git a/glloyd_and_dbetteridge/src/main.rs b/glloyd_and_dbetteridge/src/main.rs index 09e315c..2f90775 100644 --- a/glloyd_and_dbetteridge/src/main.rs +++ b/glloyd_and_dbetteridge/src/main.rs @@ -1,12 +1,12 @@ -use tennis::Game; +use tennis::{Game, Player}; fn main() { let mut game = Game::new(); - println!("Starting game: {}", game.print_score()); + println!("Starting game: {}", game); - game.point_for_player_one(); - println!("After player 1 scores: {}", game.print_score()); + game.score_point(Player::One); + println!("After player 1 scores: {}", game); - game.point_for_player_two(); - println!("After player 2 scores: {}", game.print_score()); + game.score_point(Player::Two); + println!("After player 2 scores: {}", game); } From 57ba6d85a14f75c8941caa664e82c65ffb323649 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Thu, 10 Jul 2025 00:33:25 +0100 Subject: [PATCH 13/15] wip --- glloyd_and_dbetteridge/src/lib.rs | 28 +++++++++++----------------- glloyd_and_dbetteridge/src/main.rs | 2 +- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/glloyd_and_dbetteridge/src/lib.rs b/glloyd_and_dbetteridge/src/lib.rs index 0370079..8bca7c0 100644 --- a/glloyd_and_dbetteridge/src/lib.rs +++ b/glloyd_and_dbetteridge/src/lib.rs @@ -63,22 +63,17 @@ impl Default for Game { impl Display for Game { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let score_text = match self { - Self::Deuce => "Deuce", - Self::Advantage(player) => return write!(f, "Advantage {}", player), - Self::Win(player) => return write!(f, "{} has won", player), - Self::Scores(lhs, rhs) if lhs == rhs => return write!(f, "{}-all", lhs), - Self::Scores(lhs, rhs) => return write!(f, "{}-{}", lhs, rhs), - }; - write!(f, "{}", score_text) + match self { + Self::Deuce => write!(f, "Deuce"), + Self::Advantage(player) => write!(f, "Advantage {}", player), + Self::Win(player) => write!(f, "{} has won", player), + Self::Scores(lhs, rhs) if lhs == rhs => write!(f, "{}-all", lhs), + Self::Scores(lhs, rhs) => write!(f, "{}-{}", lhs, rhs), + } } } impl Game { - pub fn new() -> Self { - Self::default() - } - pub fn advance_score(self, player: Player) -> Self { match (player, self) { (x, Self::Advantage(y)) if x != y => Self::Deuce, @@ -104,7 +99,6 @@ impl Game { pub fn score_point(&mut self, player: Player) { *self = self.advance_score(player); } - } #[cfg(test)] @@ -125,12 +119,12 @@ mod tests { #[case(vec!(3,3,2), "Player 1 has won")] #[case(vec!(3,3,1,1), "Deuce")] fn test_tennis_scoring(#[case] sequence: Vec, #[case] expected: &str) { - let mut game = Game::new(); + let mut game = Game::default(); - for (i, &n) in sequence.iter().enumerate() { - let player = if i % 2 == 0 { Player::One } else { Player::Two }; + let player_cycle = [Player::One, Player::Two].iter().cycle(); + for (&n, player) in sequence.iter().zip(player_cycle) { for _ in 0..n { - game.score_point(player); + game.score_point(*player); } } diff --git a/glloyd_and_dbetteridge/src/main.rs b/glloyd_and_dbetteridge/src/main.rs index 2f90775..237dac4 100644 --- a/glloyd_and_dbetteridge/src/main.rs +++ b/glloyd_and_dbetteridge/src/main.rs @@ -1,7 +1,7 @@ use tennis::{Game, Player}; fn main() { - let mut game = Game::new(); + let mut game = Game::default(); println!("Starting game: {}", game); game.score_point(Player::One); From c43ec9e082628c443f2e381e4729ce3891dd4712 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Thu, 10 Jul 2025 00:39:25 +0100 Subject: [PATCH 14/15] wip --- glloyd_and_dbetteridge/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/glloyd_and_dbetteridge/src/lib.rs b/glloyd_and_dbetteridge/src/lib.rs index 8bca7c0..a5690f5 100644 --- a/glloyd_and_dbetteridge/src/lib.rs +++ b/glloyd_and_dbetteridge/src/lib.rs @@ -118,6 +118,16 @@ mod tests { #[case(vec!(3,3,1), "Advantage Player 1")] #[case(vec!(3,3,2), "Player 1 has won")] #[case(vec!(3,3,1,1), "Deuce")] + #[case(vec!(0,4), "Player 2 has won")] + #[case(vec!(1,1), "15-all")] + #[case(vec!(2,2), "30-all")] + #[case(vec!(1,2), "15-30")] + #[case(vec!(2,1), "30-15")] + #[case(vec!(3,3,0,1), "Advantage Player 2")] + #[case(vec!(3,3,0,2), "Player 2 has won")] + #[case(vec!(0,3,1), "15-40")] + #[case(vec!(3,3,1,1,0,1), "Advantage Player 2")] + #[case(vec!(3,3,1,1,1,1,0,2), "Player 2 has won")] fn test_tennis_scoring(#[case] sequence: Vec, #[case] expected: &str) { let mut game = Game::default(); From 0b99db36659f1a259f4949b70df8c9b7b6d5de20 Mon Sep 17 00:00:00 2001 From: Gareth Lloyd Date: Thu, 10 Jul 2025 00:46:12 +0100 Subject: [PATCH 15/15] wip --- glloyd_and_dbetteridge/src/lib.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/glloyd_and_dbetteridge/src/lib.rs b/glloyd_and_dbetteridge/src/lib.rs index a5690f5..87b3db6 100644 --- a/glloyd_and_dbetteridge/src/lib.rs +++ b/glloyd_and_dbetteridge/src/lib.rs @@ -10,23 +10,23 @@ pub enum PlayerScore { impl Display for PlayerScore { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let str = match self { + let score_text = match self { Self::Love => "love", Self::Fifteen => "15", Self::Thirty => "30", Self::Forty => "40", }; - write!(f, "{}", str) + write!(f, "{}", score_text) } } impl PlayerScore { - fn advance_score(self) -> Self { + fn next(self) -> Self { match self { Self::Love => Self::Fifteen, Self::Fifteen => Self::Thirty, Self::Thirty => Self::Forty, - Self::Forty => Self::Forty, + Self::Forty => unreachable!("Cannot advance from Forty in regular scoring"), } } } @@ -47,11 +47,11 @@ pub enum Player { impl Display for Player { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let str = match self { + let player_text = match self { Player::One => "Player 1", Player::Two => "Player 2", }; - write!(f, "{}", str) + write!(f, "{}", player_text) } } @@ -64,17 +64,17 @@ impl Default for Game { impl Display for Game { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Deuce => write!(f, "Deuce"), + Self::Deuce => f.write_str("Deuce"), Self::Advantage(player) => write!(f, "Advantage {}", player), Self::Win(player) => write!(f, "{} has won", player), - Self::Scores(lhs, rhs) if lhs == rhs => write!(f, "{}-all", lhs), - Self::Scores(lhs, rhs) => write!(f, "{}-{}", lhs, rhs), + Self::Scores(player1_score, player2_score) if player1_score == player2_score => write!(f, "{}-all", player1_score), + Self::Scores(player1_score, player2_score) => write!(f, "{}-{}", player1_score, player2_score), } } } impl Game { - pub fn advance_score(self, player: Player) -> Self { + fn advance_score(self, player: Player) -> Self { match (player, self) { (x, Self::Advantage(y)) if x != y => Self::Deuce, (Player::One, Self::Scores(PlayerScore::Thirty, PlayerScore::Forty)) => Self::Deuce, @@ -86,11 +86,11 @@ impl Game { (Player::One, Self::Scores(PlayerScore::Forty, _)) => Self::Win(Player::One), (Player::Two, Self::Scores(_, PlayerScore::Forty)) => Self::Win(Player::Two), - (Player::One, Self::Scores(player1, player2)) => { - Self::Scores(player1.advance_score(), player2) + (Player::One, Self::Scores(player1_score, player2_score)) => { + Self::Scores(player1_score.next(), player2_score) } - (Player::Two, Self::Scores(player1, player2)) => { - Self::Scores(player1, player2.advance_score()) + (Player::Two, Self::Scores(player1_score, player2_score)) => { + Self::Scores(player1_score, player2_score.next()) } (_, x) => x, }