From c10584f2322742af5b12469d69179373fd798e95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?U=C4=9Fur=20K=C3=BCpeli?= Date: Sun, 3 Jul 2022 12:33:05 +0300 Subject: [PATCH 01/19] init --- 04_Awari/rust/Cargo.toml | 8 ++ 04_Awari/rust/src/main.rs | 179 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 04_Awari/rust/Cargo.toml create mode 100644 04_Awari/rust/src/main.rs diff --git a/04_Awari/rust/Cargo.toml b/04_Awari/rust/Cargo.toml new file mode 100644 index 00000000..1ec69633 --- /dev/null +++ b/04_Awari/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/04_Awari/rust/src/main.rs b/04_Awari/rust/src/main.rs new file mode 100644 index 00000000..4c1b4a14 --- /dev/null +++ b/04_Awari/rust/src/main.rs @@ -0,0 +1,179 @@ +fn main() { + loop { + let mut game = Game::default(); + + loop { + game.draw(); + if game.play_turn(false) { + break; + } + } + } +} + +enum DistributeResult { + Normal, // Leftover beans + EndOnHomePit(bool), // "true" if ended on Player Home Pit + EndOnEmptyPit(usize), // "index" of the empty pit within the Row + ChosenEmpty, + GameOver, +} + +struct Game { + pits: [u8; 14], + player_turn: bool, +} + +impl Default for Game { + fn default() -> Self { + println!("\t\t\t AWARI"); + println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + + Self { + pits: [3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0], + player_turn: true, + } + } +} + +impl Game { + fn step_through(&mut self, mut index: usize) -> usize { + let mut bean_amount = self.pits[index]; + + loop { + self.pits[index] += 1; + + bean_amount -= 1; + if bean_amount == 0 { + return index; + } + + index += 1; + if index > self.pits.len() - 1 { + index = 0; + } + } + } + + fn play_turn(&mut self, is_repeat: bool) -> bool { + use DistributeResult::*; + + let chosen_index = if self.player_turn { + player_prompt(if is_repeat { "Again?" } else { "Your move?" }) + } else { + println!("My move is "); + 0 // ai choice + }; + + match self.process_choice(chosen_index) { + Normal => (), + EndOnHomePit(player) => { + if player == self.player_turn && !is_repeat { + self.play_turn(true); + } + } + EndOnEmptyPit(last_index) => { + let opposite_index = 12 - last_index; + let home_index = if self.player_turn { 6 } else { 13 }; + let won_beans = 1 + self.pits[opposite_index]; + + self.pits[last_index] = 0; + self.pits[opposite_index] = 0; + self.pits[home_index] += won_beans; + } + ChosenEmpty => { + println!("Chosen pit is empty"); + return self.play_turn(is_repeat); + } + GameOver => { + let (player_beans, ai_beans) = (self.pits[6], self.pits[13]); + if player_beans == ai_beans { + println!("It's a draw") + } else if player_beans > ai_beans { + println!("You win by {}", player_beans - ai_beans); + } else { + println!("I win by {}", ai_beans - player_beans); + } + return true; + } + } + self.player_turn = !self.player_turn; + false + } + + pub fn process_choice(&mut self, index: usize) -> DistributeResult { + use DistributeResult::*; + + if self.pits[index + 1] == 0 { + return ChosenEmpty; + } + + let last_index = self.step_through(index + 1); + + if self.is_gameover() { + return GameOver; + } else if last_index == 6 && self.player_turn { + return EndOnHomePit(true); + } else if last_index == 13 && !self.player_turn { + return EndOnHomePit(false); + } else if self.pits[last_index] == 1 { + return EndOnEmptyPit(last_index); + } + + Normal + } + + fn is_gameover(&self) -> bool { + for (i, p) in self.pits.iter().enumerate() { + if i != 6 || i != 13 { + if *p > 0 { + return false; + } + } + } + true + } + + fn draw(&self) { + let row_as_string = |player: bool| -> String { + let mut row_as_string = String::new(); + let range = if player { 0..6 } else { 7..13 }; + range.for_each(|i| { + let mut bean_amount_as_string = self.pits[i].to_string(); + bean_amount_as_string.push_str(" "); + row_as_string.push_str(&bean_amount_as_string); + }); + return row_as_string; + }; + + println!( + " {}\n{}\t\t {}\n {}", + row_as_string(false), + self.pits[13].to_string(), + self.pits[6].to_string(), + row_as_string(true) + ); + } +} + +pub fn player_prompt(message: &str) -> usize { + loop { + let mut input = String::new(); + println!("{}", message); + + if let Ok(_) = std::io::stdin().read_line(&mut input) { + match input.trim().parse::() { + Ok(n) => { + if (1..=6).contains(&n) { + return n; + } else { + println!("Enter a number between 1 and 6") + } + } + Err(e) => { + println!("{}", e); + } + } + } + } +} From d1d0ef9e57478e5b8e924f0d9d52c5a228bb70a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?U=C4=9Fur=20K=C3=BCpeli?= Date: Sun, 3 Jul 2022 14:50:32 +0300 Subject: [PATCH 02/19] rust implementation --- 04_Awari/rust/Cargo.toml | 1 + 04_Awari/rust/src/main.rs | 119 ++++++++++++++++++++++++-------------- 2 files changed, 78 insertions(+), 42 deletions(-) diff --git a/04_Awari/rust/Cargo.toml b/04_Awari/rust/Cargo.toml index 1ec69633..1c2935d4 100644 --- a/04_Awari/rust/Cargo.toml +++ b/04_Awari/rust/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +rand = "0.8.5" \ No newline at end of file diff --git a/04_Awari/rust/src/main.rs b/04_Awari/rust/src/main.rs index 4c1b4a14..7aa00831 100644 --- a/04_Awari/rust/src/main.rs +++ b/04_Awari/rust/src/main.rs @@ -1,3 +1,9 @@ +use std::{thread, time::Duration}; + +use rand::Rng; + +// AI "learning" is not implemented. Don't have the time. - Ugur + fn main() { loop { let mut game = Game::default(); @@ -12,11 +18,13 @@ fn main() { } enum DistributeResult { - Normal, // Leftover beans - EndOnHomePit(bool), // "true" if ended on Player Home Pit - EndOnEmptyPit(usize), // "index" of the empty pit within the Row + Normal, + // Leftover beans + EndOnHomePit(bool), + // "true" if ended on Player Home Pit + EndOnEmptyPit(usize), + // "index" of the empty pit within the Row ChosenEmpty, - GameOver, } struct Game { @@ -26,7 +34,7 @@ struct Game { impl Default for Game { fn default() -> Self { - println!("\t\t\t AWARI"); + println!("\n\n\t\t AWARI"); println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); Self { @@ -39,35 +47,68 @@ impl Default for Game { impl Game { fn step_through(&mut self, mut index: usize) -> usize { let mut bean_amount = self.pits[index]; + self.pits[index] = 0; loop { + index += 1; + + if index > self.pits.len() - 1 { + index = 0; + } + self.pits[index] += 1; bean_amount -= 1; if bean_amount == 0 { return index; } - - index += 1; - if index > self.pits.len() - 1 { - index = 0; - } } } fn play_turn(&mut self, is_repeat: bool) -> bool { use DistributeResult::*; + if self.is_game_over() { + println!("\nGame Over!"); + let (player_beans, ai_beans) = (self.pits[6], self.pits[13]); + if player_beans == ai_beans { + println!("It's a draw") + } else if player_beans > ai_beans { + println!("You win by {}", player_beans - ai_beans); + } else { + println!("I win by {}", ai_beans - player_beans); + } + return true; + } + let chosen_index = if self.player_turn { - player_prompt(if is_repeat { "Again?" } else { "Your move?" }) + player_prompt(if is_repeat { "Again?" } else { "Your move?" }) - 1 } else { - println!("My move is "); - 0 // ai choice + println!("========================"); + + thread::sleep(Duration::from_secs(1)); + + let non_empty_pits: Vec = self + .pits + .iter() + .enumerate() + .filter(|&(i, p)| (7..13).contains(&i) && *p > 0) + .map(|(i, _)| i) + .collect(); + let random_index = rand::thread_rng().gen_range(0..non_empty_pits.len()); + let ai_move = non_empty_pits[random_index]; + + println!("My move is {}", ai_move - 6); + + println!("========================"); + ai_move }; match self.process_choice(chosen_index) { Normal => (), EndOnHomePit(player) => { + self.draw(); + if player == self.player_turn && !is_repeat { self.play_turn(true); } @@ -85,34 +126,25 @@ impl Game { println!("Chosen pit is empty"); return self.play_turn(is_repeat); } - GameOver => { - let (player_beans, ai_beans) = (self.pits[6], self.pits[13]); - if player_beans == ai_beans { - println!("It's a draw") - } else if player_beans > ai_beans { - println!("You win by {}", player_beans - ai_beans); - } else { - println!("I win by {}", ai_beans - player_beans); - } - return true; - } } - self.player_turn = !self.player_turn; + + if !is_repeat { + self.player_turn = !self.player_turn; + } + false } pub fn process_choice(&mut self, index: usize) -> DistributeResult { use DistributeResult::*; - if self.pits[index + 1] == 0 { + if self.pits[index] == 0 { return ChosenEmpty; } - let last_index = self.step_through(index + 1); + let last_index = self.step_through(index); - if self.is_gameover() { - return GameOver; - } else if last_index == 6 && self.player_turn { + if last_index == 6 && self.player_turn { return EndOnHomePit(true); } else if last_index == 13 && !self.player_turn { return EndOnHomePit(false); @@ -123,31 +155,34 @@ impl Game { Normal } - fn is_gameover(&self) -> bool { - for (i, p) in self.pits.iter().enumerate() { - if i != 6 || i != 13 { - if *p > 0 { - return false; - } - } - } - true + fn is_game_over(&self) -> bool { + let player_empty = !(0..6).any(|i| self.pits[i] > 0); + let ai_empty = !(7..13).any(|i| self.pits[i] > 0); + player_empty || ai_empty } fn draw(&self) { let row_as_string = |player: bool| -> String { let mut row_as_string = String::new(); + let range = if player { 0..6 } else { 7..13 }; + range.for_each(|i| { let mut bean_amount_as_string = self.pits[i].to_string(); bean_amount_as_string.push_str(" "); - row_as_string.push_str(&bean_amount_as_string); + + if player { + row_as_string.push_str(&bean_amount_as_string); + } else { + row_as_string.insert_str(0, &bean_amount_as_string); + } }); - return row_as_string; + + row_as_string }; println!( - " {}\n{}\t\t {}\n {}", + "\n {}\n{} {}\n {}\n", row_as_string(false), self.pits[13].to_string(), self.pits[6].to_string(), From 832371dc07f83ec64e194349cf20af18678b3053 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 6 Jul 2022 07:46:16 +1000 Subject: [PATCH 03/19] Add string resources --- 16_Bug/csharp/Bug.csproj | 9 +++++++++ 16_Bug/csharp/Resources/Introduction.txt | 7 +++++++ 16_Bug/csharp/Resources/Intructions.txt | 18 ++++++++++++++++++ 16_Bug/csharp/Resources/Resource.cs | 24 ++++++++++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 16_Bug/csharp/Resources/Introduction.txt create mode 100644 16_Bug/csharp/Resources/Intructions.txt create mode 100644 16_Bug/csharp/Resources/Resource.cs diff --git a/16_Bug/csharp/Bug.csproj b/16_Bug/csharp/Bug.csproj index d3fe4757..91e759c0 100644 --- a/16_Bug/csharp/Bug.csproj +++ b/16_Bug/csharp/Bug.csproj @@ -6,4 +6,13 @@ enable enable + + + + + + + + + diff --git a/16_Bug/csharp/Resources/Introduction.txt b/16_Bug/csharp/Resources/Introduction.txt new file mode 100644 index 00000000..b49238e6 --- /dev/null +++ b/16_Bug/csharp/Resources/Introduction.txt @@ -0,0 +1,7 @@ + Bug + Creative Computing Morristown, New Jersey + + + +The Game Bug +I hope you enjoy this game. diff --git a/16_Bug/csharp/Resources/Intructions.txt b/16_Bug/csharp/Resources/Intructions.txt new file mode 100644 index 00000000..bdbdadd3 --- /dev/null +++ b/16_Bug/csharp/Resources/Intructions.txt @@ -0,0 +1,18 @@ +The object of Bug is to finish your bug before I finish +mine. Each number stands for a part of the bug body. +I will roll the die for you, tell you what I rolled for you +what the number stands for, and if you can get the part. +If you can get the part I will give it to you. +The same will happen on my turn. +If there is a change in either bug I will give you the +option of seeing the pictures of the bugs. +The numbers stand for parts as follows: +Number Part Number of part needed + 1 Body 1 + 2 Neck 1 + 3 Head 1 + 4 Feelers 2 + 5 Tail 1 + 6 Legs 6 + + diff --git a/16_Bug/csharp/Resources/Resource.cs b/16_Bug/csharp/Resources/Resource.cs new file mode 100644 index 00000000..165b9c82 --- /dev/null +++ b/16_Bug/csharp/Resources/Resource.cs @@ -0,0 +1,24 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Bug.Resources; + +internal static class Resource +{ + internal static class Streams + { + public static Stream Introduction => GetStream(); + public static Stream Instructions => GetStream(); + } + + private static string GetString([CallerMemberName] string? name = null) + { + using var stream = GetStream(name); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + private static Stream GetStream([CallerMemberName] string? name = null) => + Assembly.GetExecutingAssembly().GetManifestResourceStream($"Basketball.Resources.{name}.txt") + ?? throw new Exception($"Could not find embedded resource stream '{name}'."); +} \ No newline at end of file From ffc0b99fa3c57d8279c1334832893b7ffd27bf4f Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 6 Jul 2022 07:48:01 +1000 Subject: [PATCH 04/19] Display title and instructions --- 16_Bug/csharp/Game.cs | 25 +++++++++++++++++++++++++ 16_Bug/csharp/Program.cs | 4 ++++ 2 files changed, 29 insertions(+) create mode 100644 16_Bug/csharp/Game.cs create mode 100644 16_Bug/csharp/Program.cs diff --git a/16_Bug/csharp/Game.cs b/16_Bug/csharp/Game.cs new file mode 100644 index 00000000..b82c270d --- /dev/null +++ b/16_Bug/csharp/Game.cs @@ -0,0 +1,25 @@ +using Bug.Resources; +using Games.Common.IO; +using Games.Common.Randomness; + +internal class Game +{ + private readonly IReadWrite _io; + private readonly IRandom _random; + + public Game(IReadWrite io, IRandom random) + { + _io = io; + _random = random; + } + + public void Play() + { + _io.WriteLine(Resource.Streams.Introduction); + var response = _io.ReadString("Do you want instructions"); + if (!response.Equals("no", StringComparison.InvariantCultureIgnoreCase)) + { + _io.WriteLine(Resource.Streams.Instructions); + } + } +} \ No newline at end of file diff --git a/16_Bug/csharp/Program.cs b/16_Bug/csharp/Program.cs new file mode 100644 index 00000000..bb3d85aa --- /dev/null +++ b/16_Bug/csharp/Program.cs @@ -0,0 +1,4 @@ +using Games.Common.IO; +using Games.Common.Randomness; + +new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); From f35bbb02243a82802888fc0d95e928a6b8cf0573 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 6 Jul 2022 07:52:59 +1000 Subject: [PATCH 05/19] Fix some resource issues --- 16_Bug/csharp/Game.cs | 4 ++-- 16_Bug/csharp/Resources/{Intructions.txt => Instructions.txt} | 0 16_Bug/csharp/Resources/Introduction.txt | 1 + 16_Bug/csharp/Resources/Resource.cs | 3 ++- 4 files changed, 5 insertions(+), 3 deletions(-) rename 16_Bug/csharp/Resources/{Intructions.txt => Instructions.txt} (100%) diff --git a/16_Bug/csharp/Game.cs b/16_Bug/csharp/Game.cs index b82c270d..f1bc1291 100644 --- a/16_Bug/csharp/Game.cs +++ b/16_Bug/csharp/Game.cs @@ -15,11 +15,11 @@ internal class Game public void Play() { - _io.WriteLine(Resource.Streams.Introduction); + _io.Write(Resource.Streams.Introduction); var response = _io.ReadString("Do you want instructions"); if (!response.Equals("no", StringComparison.InvariantCultureIgnoreCase)) { - _io.WriteLine(Resource.Streams.Instructions); + _io.Write(Resource.Streams.Instructions); } } } \ No newline at end of file diff --git a/16_Bug/csharp/Resources/Intructions.txt b/16_Bug/csharp/Resources/Instructions.txt similarity index 100% rename from 16_Bug/csharp/Resources/Intructions.txt rename to 16_Bug/csharp/Resources/Instructions.txt diff --git a/16_Bug/csharp/Resources/Introduction.txt b/16_Bug/csharp/Resources/Introduction.txt index b49238e6..e74a833e 100644 --- a/16_Bug/csharp/Resources/Introduction.txt +++ b/16_Bug/csharp/Resources/Introduction.txt @@ -5,3 +5,4 @@ The Game Bug I hope you enjoy this game. + diff --git a/16_Bug/csharp/Resources/Resource.cs b/16_Bug/csharp/Resources/Resource.cs index 165b9c82..51b7bf39 100644 --- a/16_Bug/csharp/Resources/Resource.cs +++ b/16_Bug/csharp/Resources/Resource.cs @@ -19,6 +19,7 @@ internal static class Resource } private static Stream GetStream([CallerMemberName] string? name = null) => - Assembly.GetExecutingAssembly().GetManifestResourceStream($"Basketball.Resources.{name}.txt") + Assembly.GetExecutingAssembly() + .GetManifestResourceStream($"{typeof(Resource).Namespace}.{name}.txt") ?? throw new Exception($"Could not find embedded resource stream '{name}'."); } \ No newline at end of file From 6078da8c783a7e449b847b8d34adcef997861150 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Mon, 11 Jul 2022 08:46:42 +1000 Subject: [PATCH 06/19] Add parts and messages --- 16_Bug/csharp/Game.cs | 4 ++- 16_Bug/csharp/Parts/Body.cs | 25 ++++++++++++++++ 16_Bug/csharp/Parts/Feeler.cs | 6 ++++ 16_Bug/csharp/Parts/Feelers.cs | 11 +++++++ 16_Bug/csharp/Parts/Head.cs | 20 +++++++++++++ 16_Bug/csharp/Parts/IPart.cs | 6 ++++ 16_Bug/csharp/Parts/Leg.cs | 6 ++++ 16_Bug/csharp/Parts/Legs.cs | 11 +++++++ 16_Bug/csharp/Parts/Neck.cs | 21 ++++++++++++++ 16_Bug/csharp/Parts/ParentPart.cs | 22 ++++++++++++++ 16_Bug/csharp/Parts/Part.cs | 32 ++++++++++++++++++++ 16_Bug/csharp/Parts/PartCollection.cs | 31 ++++++++++++++++++++ 16_Bug/csharp/Parts/Tail.cs | 11 +++++++ 16_Bug/csharp/Program.cs | 1 + 16_Bug/csharp/Resources/Message.cs | 42 +++++++++++++++++++++++++++ 16_Bug/csharp/Resources/Resource.cs | 2 +- 16 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 16_Bug/csharp/Parts/Body.cs create mode 100644 16_Bug/csharp/Parts/Feeler.cs create mode 100644 16_Bug/csharp/Parts/Feelers.cs create mode 100644 16_Bug/csharp/Parts/Head.cs create mode 100644 16_Bug/csharp/Parts/IPart.cs create mode 100644 16_Bug/csharp/Parts/Leg.cs create mode 100644 16_Bug/csharp/Parts/Legs.cs create mode 100644 16_Bug/csharp/Parts/Neck.cs create mode 100644 16_Bug/csharp/Parts/ParentPart.cs create mode 100644 16_Bug/csharp/Parts/Part.cs create mode 100644 16_Bug/csharp/Parts/PartCollection.cs create mode 100644 16_Bug/csharp/Parts/Tail.cs create mode 100644 16_Bug/csharp/Resources/Message.cs diff --git a/16_Bug/csharp/Game.cs b/16_Bug/csharp/Game.cs index f1bc1291..c98c44f5 100644 --- a/16_Bug/csharp/Game.cs +++ b/16_Bug/csharp/Game.cs @@ -1,7 +1,9 @@ -using Bug.Resources; +using BugGame.Resources; using Games.Common.IO; using Games.Common.Randomness; +namespace BugGame; + internal class Game { private readonly IReadWrite _io; diff --git a/16_Bug/csharp/Parts/Body.cs b/16_Bug/csharp/Parts/Body.cs new file mode 100644 index 00000000..61aad080 --- /dev/null +++ b/16_Bug/csharp/Parts/Body.cs @@ -0,0 +1,25 @@ +using BugGame.Resources; + +namespace BugGame.Parts; + +internal class Body : ParentPart +{ + private readonly Neck _neck = new(); + private readonly Tail _tail = new(); + private readonly Legs _legs = new(); + + public Body() + : base(Message.BodyAdded, Message.BodyNotNeeded) + { + } + + protected override bool TryAddCore(IPart part, out Message message) + => part switch + { + Neck => _neck.TryAdd(out message), + Head or Feeler => _neck.TryAdd(part, out message), + Tail => _tail.TryAdd(out message), + Leg => _legs.TryAddOne(out message), + _ => throw new NotSupportedException($"Can't add a {part.Name} to a {Name}.") + }; +} diff --git a/16_Bug/csharp/Parts/Feeler.cs b/16_Bug/csharp/Parts/Feeler.cs new file mode 100644 index 00000000..9508d541 --- /dev/null +++ b/16_Bug/csharp/Parts/Feeler.cs @@ -0,0 +1,6 @@ +namespace BugGame.Parts; + +internal class Feeler : IPart +{ + public string Name => nameof(Feeler); +} diff --git a/16_Bug/csharp/Parts/Feelers.cs b/16_Bug/csharp/Parts/Feelers.cs new file mode 100644 index 00000000..fca80c33 --- /dev/null +++ b/16_Bug/csharp/Parts/Feelers.cs @@ -0,0 +1,11 @@ +using BugGame.Resources; + +namespace BugGame.Parts; + +internal class Feelers : PartCollection +{ + public Feelers() + : base(6, Message.FeelerAdded, Message.FeelersFull) + { + } +} diff --git a/16_Bug/csharp/Parts/Head.cs b/16_Bug/csharp/Parts/Head.cs new file mode 100644 index 00000000..2d5e705d --- /dev/null +++ b/16_Bug/csharp/Parts/Head.cs @@ -0,0 +1,20 @@ +using BugGame.Resources; + +namespace BugGame.Parts; + +internal class Head : ParentPart +{ + private Feelers _feelers = new(); + + public Head() + : base(Message.HeadAdded, Message.HeadNotNeeded) + { + } + + protected override bool TryAddCore(IPart part, out Message message) + => part switch + { + Feeler => _feelers.TryAddOne(out message), + _ => throw new NotSupportedException($"Can't add a {part.Name} to a {Name}.") + }; +} diff --git a/16_Bug/csharp/Parts/IPart.cs b/16_Bug/csharp/Parts/IPart.cs new file mode 100644 index 00000000..e325a7c1 --- /dev/null +++ b/16_Bug/csharp/Parts/IPart.cs @@ -0,0 +1,6 @@ +namespace BugGame.Parts; + +internal interface IPart +{ + string Name { get; } +} diff --git a/16_Bug/csharp/Parts/Leg.cs b/16_Bug/csharp/Parts/Leg.cs new file mode 100644 index 00000000..c2d4aaaf --- /dev/null +++ b/16_Bug/csharp/Parts/Leg.cs @@ -0,0 +1,6 @@ +namespace BugGame.Parts; + +internal class Leg : IPart +{ + public string Name => nameof(Leg); +} diff --git a/16_Bug/csharp/Parts/Legs.cs b/16_Bug/csharp/Parts/Legs.cs new file mode 100644 index 00000000..b108e2ea --- /dev/null +++ b/16_Bug/csharp/Parts/Legs.cs @@ -0,0 +1,11 @@ +using BugGame.Resources; + +namespace BugGame.Parts; + +internal class Legs : PartCollection +{ + public Legs() + : base(2, Message.LegAdded, Message.LegsFull) + { + } +} diff --git a/16_Bug/csharp/Parts/Neck.cs b/16_Bug/csharp/Parts/Neck.cs new file mode 100644 index 00000000..035d0c18 --- /dev/null +++ b/16_Bug/csharp/Parts/Neck.cs @@ -0,0 +1,21 @@ +using BugGame.Resources; + +namespace BugGame.Parts; + +internal class Neck : ParentPart +{ + private Head _head = new(); + + public Neck() + : base(Message.NeckAdded, Message.NeckNotNeeded) + { + } + + protected override bool TryAddCore(IPart part, out Message message) + => part switch + { + Head => _head.TryAdd(out message), + Feeler => _head.TryAdd(part, out message), + _ => throw new NotSupportedException($"Can't add a {part.Name} to a {Name}.") + }; +} diff --git a/16_Bug/csharp/Parts/ParentPart.cs b/16_Bug/csharp/Parts/ParentPart.cs new file mode 100644 index 00000000..78a21d6e --- /dev/null +++ b/16_Bug/csharp/Parts/ParentPart.cs @@ -0,0 +1,22 @@ +using BugGame.Resources; + +namespace BugGame.Parts; + +internal abstract class ParentPart : Part +{ + public ParentPart(Message addedMessage, Message duplicateMessage) + : base(addedMessage, duplicateMessage) + { + } + + public bool TryAdd(IPart part, out Message message) + => IsPresent ? TryAddCore(part, out message) : ReportDoNotHave(out message); + + protected abstract bool TryAddCore(IPart part, out Message message); + + private bool ReportDoNotHave(out Message message) + { + message = Message.DoNotHaveA(this); + return false; + } +} diff --git a/16_Bug/csharp/Parts/Part.cs b/16_Bug/csharp/Parts/Part.cs new file mode 100644 index 00000000..a1a5d64d --- /dev/null +++ b/16_Bug/csharp/Parts/Part.cs @@ -0,0 +1,32 @@ +using BugGame.Resources; + +namespace BugGame.Parts; + +internal class Part +{ + private readonly Message _addedMessage; + private readonly Message _duplicateMessage; + + public Part(Message addedMessage, Message duplicateMessage) + { + _addedMessage = addedMessage; + _duplicateMessage = duplicateMessage; + } + + protected bool IsPresent { get; private set; } + + public string Name => GetType().Name; + + public bool TryAdd(out Message message) + { + if (IsPresent) + { + message = _duplicateMessage; + return false; + } + + message = _addedMessage; + IsPresent = true; + return true; + } +} diff --git a/16_Bug/csharp/Parts/PartCollection.cs b/16_Bug/csharp/Parts/PartCollection.cs new file mode 100644 index 00000000..43a684b5 --- /dev/null +++ b/16_Bug/csharp/Parts/PartCollection.cs @@ -0,0 +1,31 @@ +using BugGame.Resources; + +namespace BugGame.Parts; + +internal class PartCollection +{ + private readonly int _maxCount; + private readonly Message _addedMessage; + private readonly Message _fullMessage; + private int _count; + + public PartCollection(int maxCount, Message addedMessage, Message fullMessage) + { + _maxCount = maxCount; + _addedMessage = addedMessage; + _fullMessage = fullMessage; + } + + public bool TryAddOne(out Message message) + { + if (_count < _maxCount) + { + _count++; + message = _addedMessage.ForQuantity(_count); + return true; + } + + message = _fullMessage; + return false; + } +} diff --git a/16_Bug/csharp/Parts/Tail.cs b/16_Bug/csharp/Parts/Tail.cs new file mode 100644 index 00000000..ad610d81 --- /dev/null +++ b/16_Bug/csharp/Parts/Tail.cs @@ -0,0 +1,11 @@ +using BugGame.Resources; + +namespace BugGame.Parts; + +internal class Tail : Part +{ + public Tail() + : base(Message.TailAdded, Message.TailNotNeeded) + { + } +} \ No newline at end of file diff --git a/16_Bug/csharp/Program.cs b/16_Bug/csharp/Program.cs index bb3d85aa..883e62d1 100644 --- a/16_Bug/csharp/Program.cs +++ b/16_Bug/csharp/Program.cs @@ -1,3 +1,4 @@ +using BugGame; using Games.Common.IO; using Games.Common.Randomness; diff --git a/16_Bug/csharp/Resources/Message.cs b/16_Bug/csharp/Resources/Message.cs new file mode 100644 index 00000000..5cd9f998 --- /dev/null +++ b/16_Bug/csharp/Resources/Message.cs @@ -0,0 +1,42 @@ +namespace BugGame.Resources; + +internal class Message +{ + public static Message Rolled = new("rolled a {0}"); + + public static Message BodyAdded = new("now have a body."); + public static Message BodyNotNeeded = new("do not need a body."); + + public static Message NeckAdded = new("now have a neck."); + public static Message NeckNotNeeded = new("do not need a neck."); + + public static Message HeadAdded = new("needed a head."); + public static Message HeadNotNeeded = new("I do not need a head.", "You have a head."); + + public static Message TailAdded = new("I now have a tail.", "I now give you a tail."); + public static Message TailNotNeeded = new("I do not need a tail.", "You already have a tail."); + + public static Message FeelerAdded = new("I get a feeler.", "I now give you a feeler"); + public static Message FeelersFull = new("I have 2 feelers already.", "You have two feelers already"); + + public static Message LegAdded = new("now have {0} legs"); + public static Message LegsFull = new("I have 6 feet.", "You have 6 feet already"); + + private Message(string common) + : this("I " + common, "You" + common) + { + } + + private Message(string i, string you) + { + I = i; + You = you; + } + + public string I { get; } + public string You { get; } + + public static Message DoNotHaveA(Part part) => new($"do no have a {part.Name}"); + + public Message ForQuantity(int quantity) => new(string.Format(I, quantity), string.Format(You, quantity)); +} \ No newline at end of file diff --git a/16_Bug/csharp/Resources/Resource.cs b/16_Bug/csharp/Resources/Resource.cs index 51b7bf39..57f05438 100644 --- a/16_Bug/csharp/Resources/Resource.cs +++ b/16_Bug/csharp/Resources/Resource.cs @@ -1,7 +1,7 @@ using System.Reflection; using System.Runtime.CompilerServices; -namespace Bug.Resources; +namespace BugGame.Resources; internal static class Resource { From be9f0a92f8ee48567d492dbf5a7a5ea76f51f6f8 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 12 Jul 2022 07:41:45 +1000 Subject: [PATCH 07/19] Add Bug and conecpt of completeness --- 16_Bug/csharp/Bug.cs | 13 +++++++++++++ 16_Bug/csharp/Parts/Body.cs | 2 ++ 16_Bug/csharp/Parts/Head.cs | 2 ++ 16_Bug/csharp/Parts/IPart.cs | 1 + 16_Bug/csharp/Parts/Neck.cs | 2 ++ 16_Bug/csharp/Parts/Part.cs | 2 ++ 16_Bug/csharp/Parts/PartCollection.cs | 2 ++ 16_Bug/csharp/Resources/Message.cs | 2 ++ 8 files changed, 26 insertions(+) create mode 100644 16_Bug/csharp/Bug.cs diff --git a/16_Bug/csharp/Bug.cs b/16_Bug/csharp/Bug.cs new file mode 100644 index 00000000..e013d1b6 --- /dev/null +++ b/16_Bug/csharp/Bug.cs @@ -0,0 +1,13 @@ +using BugGame.Parts; +using BugGame.Resources; + +namespace BugGame; + +internal class Bug +{ + private readonly Body _body = new(); + + public bool IsComplete => _body.IsComplete; + + public bool TryAdd(IPart part, out Message message) => _body.TryAdd(part, out message); +} \ No newline at end of file diff --git a/16_Bug/csharp/Parts/Body.cs b/16_Bug/csharp/Parts/Body.cs index 61aad080..65fde374 100644 --- a/16_Bug/csharp/Parts/Body.cs +++ b/16_Bug/csharp/Parts/Body.cs @@ -13,6 +13,8 @@ internal class Body : ParentPart { } + public override bool IsComplete => _neck.IsComplete && _tail.IsComplete && _legs.IsComplete; + protected override bool TryAddCore(IPart part, out Message message) => part switch { diff --git a/16_Bug/csharp/Parts/Head.cs b/16_Bug/csharp/Parts/Head.cs index 2d5e705d..bafa172f 100644 --- a/16_Bug/csharp/Parts/Head.cs +++ b/16_Bug/csharp/Parts/Head.cs @@ -11,6 +11,8 @@ internal class Head : ParentPart { } + public override bool IsComplete => _feelers.IsComplete; + protected override bool TryAddCore(IPart part, out Message message) => part switch { diff --git a/16_Bug/csharp/Parts/IPart.cs b/16_Bug/csharp/Parts/IPart.cs index e325a7c1..3d1a45c5 100644 --- a/16_Bug/csharp/Parts/IPart.cs +++ b/16_Bug/csharp/Parts/IPart.cs @@ -3,4 +3,5 @@ namespace BugGame.Parts; internal interface IPart { string Name { get; } + bool IsComplete { get; } } diff --git a/16_Bug/csharp/Parts/Neck.cs b/16_Bug/csharp/Parts/Neck.cs index 035d0c18..ee5853e2 100644 --- a/16_Bug/csharp/Parts/Neck.cs +++ b/16_Bug/csharp/Parts/Neck.cs @@ -11,6 +11,8 @@ internal class Neck : ParentPart { } + public override bool IsComplete => _head.IsComplete; + protected override bool TryAddCore(IPart part, out Message message) => part switch { diff --git a/16_Bug/csharp/Parts/Part.cs b/16_Bug/csharp/Parts/Part.cs index a1a5d64d..ada12b8c 100644 --- a/16_Bug/csharp/Parts/Part.cs +++ b/16_Bug/csharp/Parts/Part.cs @@ -13,6 +13,8 @@ internal class Part _duplicateMessage = duplicateMessage; } + public virtual bool IsComplete => IsPresent; + protected bool IsPresent { get; private set; } public string Name => GetType().Name; diff --git a/16_Bug/csharp/Parts/PartCollection.cs b/16_Bug/csharp/Parts/PartCollection.cs index 43a684b5..aac0bbd2 100644 --- a/16_Bug/csharp/Parts/PartCollection.cs +++ b/16_Bug/csharp/Parts/PartCollection.cs @@ -16,6 +16,8 @@ internal class PartCollection _fullMessage = fullMessage; } + public bool IsComplete => _count == _maxCount; + public bool TryAddOne(out Message message) { if (_count < _maxCount) diff --git a/16_Bug/csharp/Resources/Message.cs b/16_Bug/csharp/Resources/Message.cs index 5cd9f998..be85faf8 100644 --- a/16_Bug/csharp/Resources/Message.cs +++ b/16_Bug/csharp/Resources/Message.cs @@ -1,3 +1,5 @@ +using BugGame.Parts; + namespace BugGame.Resources; internal class Message From 04ec0f8f47a0278ed0c7f208210e6b6d87ddee0a Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 13 Jul 2022 08:04:35 +1000 Subject: [PATCH 08/19] Add printing of bugs --- 16_Bug/csharp/Bug.cs | 8 ++++++++ 16_Bug/csharp/Parts/Body.cs | 14 ++++++++++++++ 16_Bug/csharp/Parts/Feelers.cs | 5 ++++- 16_Bug/csharp/Parts/Head.cs | 13 +++++++++++++ 16_Bug/csharp/Parts/IPart.cs | 1 - 16_Bug/csharp/Parts/Legs.cs | 5 ++++- 16_Bug/csharp/Parts/Neck.cs | 7 +++++++ 16_Bug/csharp/Parts/Part.cs | 2 +- 16_Bug/csharp/Parts/PartCollection.cs | 19 ++++++++++++++++++- 16_Bug/csharp/Parts/Tail.cs | 3 +++ 10 files changed, 72 insertions(+), 5 deletions(-) diff --git a/16_Bug/csharp/Bug.cs b/16_Bug/csharp/Bug.cs index e013d1b6..42e686d4 100644 --- a/16_Bug/csharp/Bug.cs +++ b/16_Bug/csharp/Bug.cs @@ -1,3 +1,4 @@ +using System.Text; using BugGame.Parts; using BugGame.Resources; @@ -10,4 +11,11 @@ internal class Bug public bool IsComplete => _body.IsComplete; public bool TryAdd(IPart part, out Message message) => _body.TryAdd(part, out message); + + public string ToString(string pronoun, char feelerCharacter) + { + var builder = new StringBuilder($"*****{pronoun} Bug*****").AppendLine().AppendLine().AppendLine(); + _body.AppendTo(builder, feelerCharacter); + return builder.ToString(); + } } \ No newline at end of file diff --git a/16_Bug/csharp/Parts/Body.cs b/16_Bug/csharp/Parts/Body.cs index 65fde374..2b7586dc 100644 --- a/16_Bug/csharp/Parts/Body.cs +++ b/16_Bug/csharp/Parts/Body.cs @@ -1,3 +1,4 @@ +using System.Text; using BugGame.Resources; namespace BugGame.Parts; @@ -24,4 +25,17 @@ internal class Body : ParentPart Leg => _legs.TryAddOne(out message), _ => throw new NotSupportedException($"Can't add a {part.Name} to a {Name}.") }; + + public void AppendTo(StringBuilder builder, char feelerCharacter) + { + _neck.AppendTo(builder, feelerCharacter); + builder + .AppendLine(" BBBBBBBBBBBB") + .AppendLine(" B B") + .AppendLine(" B B"); + _tail.AppendTo(builder); + builder + .AppendLine(" BBBBBBBBBBBB"); + _legs.AppendTo(builder); + } } diff --git a/16_Bug/csharp/Parts/Feelers.cs b/16_Bug/csharp/Parts/Feelers.cs index fca80c33..165a073d 100644 --- a/16_Bug/csharp/Parts/Feelers.cs +++ b/16_Bug/csharp/Parts/Feelers.cs @@ -1,3 +1,4 @@ +using System.Text; using BugGame.Resources; namespace BugGame.Parts; @@ -5,7 +6,9 @@ namespace BugGame.Parts; internal class Feelers : PartCollection { public Feelers() - : base(6, Message.FeelerAdded, Message.FeelersFull) + : base(2, Message.FeelerAdded, Message.FeelersFull) { } + + public void AppendTo(StringBuilder builder, char character) => AppendTo(builder, 10, 4, character); } diff --git a/16_Bug/csharp/Parts/Head.cs b/16_Bug/csharp/Parts/Head.cs index bafa172f..3bab7caa 100644 --- a/16_Bug/csharp/Parts/Head.cs +++ b/16_Bug/csharp/Parts/Head.cs @@ -1,3 +1,4 @@ +using System.Text; using BugGame.Resources; namespace BugGame.Parts; @@ -19,4 +20,16 @@ internal class Head : ParentPart Feeler => _feelers.TryAddOne(out message), _ => throw new NotSupportedException($"Can't add a {part.Name} to a {Name}.") }; + + public void AppendTo(StringBuilder builder, char feelerCharacter) + { + _feelers.AppendTo(builder, feelerCharacter); + builder + .AppendLine(" HHHHHHH") + .AppendLine(" H H") + .AppendLine(" H O O H") + .AppendLine(" H H") + .AppendLine(" H V H") + .AppendLine(" HHHHHHH"); + } } diff --git a/16_Bug/csharp/Parts/IPart.cs b/16_Bug/csharp/Parts/IPart.cs index 3d1a45c5..e325a7c1 100644 --- a/16_Bug/csharp/Parts/IPart.cs +++ b/16_Bug/csharp/Parts/IPart.cs @@ -3,5 +3,4 @@ namespace BugGame.Parts; internal interface IPart { string Name { get; } - bool IsComplete { get; } } diff --git a/16_Bug/csharp/Parts/Legs.cs b/16_Bug/csharp/Parts/Legs.cs index b108e2ea..0ed8d8fc 100644 --- a/16_Bug/csharp/Parts/Legs.cs +++ b/16_Bug/csharp/Parts/Legs.cs @@ -1,3 +1,4 @@ +using System.Text; using BugGame.Resources; namespace BugGame.Parts; @@ -5,7 +6,9 @@ namespace BugGame.Parts; internal class Legs : PartCollection { public Legs() - : base(2, Message.LegAdded, Message.LegsFull) + : base(6, Message.LegAdded, Message.LegsFull) { } + + public void AppendTo(StringBuilder builder) => AppendTo(builder, 6, 2, 'L'); } diff --git a/16_Bug/csharp/Parts/Neck.cs b/16_Bug/csharp/Parts/Neck.cs index ee5853e2..e8976c1c 100644 --- a/16_Bug/csharp/Parts/Neck.cs +++ b/16_Bug/csharp/Parts/Neck.cs @@ -1,3 +1,4 @@ +using System.Text; using BugGame.Resources; namespace BugGame.Parts; @@ -20,4 +21,10 @@ internal class Neck : ParentPart Feeler => _head.TryAdd(part, out message), _ => throw new NotSupportedException($"Can't add a {part.Name} to a {Name}.") }; + + public void AppendTo(StringBuilder builder, char feelerCharacter) + { + _head.AppendTo(builder, feelerCharacter); + builder.AppendLine(" N N").AppendLine(" N N"); + } } diff --git a/16_Bug/csharp/Parts/Part.cs b/16_Bug/csharp/Parts/Part.cs index ada12b8c..f29fbd81 100644 --- a/16_Bug/csharp/Parts/Part.cs +++ b/16_Bug/csharp/Parts/Part.cs @@ -2,7 +2,7 @@ using BugGame.Resources; namespace BugGame.Parts; -internal class Part +internal class Part : IPart { private readonly Message _addedMessage; private readonly Message _duplicateMessage; diff --git a/16_Bug/csharp/Parts/PartCollection.cs b/16_Bug/csharp/Parts/PartCollection.cs index aac0bbd2..6e6034de 100644 --- a/16_Bug/csharp/Parts/PartCollection.cs +++ b/16_Bug/csharp/Parts/PartCollection.cs @@ -1,3 +1,4 @@ +using System.Text; using BugGame.Resources; namespace BugGame.Parts; @@ -23,11 +24,27 @@ internal class PartCollection if (_count < _maxCount) { _count++; - message = _addedMessage.ForQuantity(_count); + message = _addedMessage.ForValue(_count); return true; } message = _fullMessage; return false; } + + protected void AppendTo(StringBuilder builder, int offset, int length, char character) + { + if (_count == 0) { return; } + + builder.Append(' ', offset); + + for (var i = 0; i < length; i++) + { + for (var j = 0; j < _count; j++) + { + builder.Append(character).Append(' '); + } + builder.AppendLine(); + } + } } diff --git a/16_Bug/csharp/Parts/Tail.cs b/16_Bug/csharp/Parts/Tail.cs index ad610d81..8c450f1d 100644 --- a/16_Bug/csharp/Parts/Tail.cs +++ b/16_Bug/csharp/Parts/Tail.cs @@ -1,3 +1,4 @@ +using System.Text; using BugGame.Resources; namespace BugGame.Parts; @@ -8,4 +9,6 @@ internal class Tail : Part : base(Message.TailAdded, Message.TailNotNeeded) { } + + public void AppendTo(StringBuilder builder) => builder.AppendLine("TTTTTB B"); } \ No newline at end of file From 013baf71a2058c9403ae26041cf8dced651a7971 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 13 Jul 2022 08:04:47 +1000 Subject: [PATCH 09/19] Add game loop --- 16_Bug/csharp/Game.cs | 56 +++++++++++++++++++++++++-- 16_Bug/csharp/Resources/Message.cs | 4 +- 16_Bug/csharp/Resources/PlayAgain.txt | 1 + 16_Bug/csharp/Resources/Resource.cs | 10 +---- 4 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 16_Bug/csharp/Resources/PlayAgain.txt diff --git a/16_Bug/csharp/Game.cs b/16_Bug/csharp/Game.cs index c98c44f5..2b5c0711 100644 --- a/16_Bug/csharp/Game.cs +++ b/16_Bug/csharp/Game.cs @@ -1,7 +1,8 @@ +using BugGame.Parts; using BugGame.Resources; using Games.Common.IO; using Games.Common.Randomness; - +using static System.StringComparison; namespace BugGame; internal class Game @@ -18,10 +19,59 @@ internal class Game public void Play() { _io.Write(Resource.Streams.Introduction); - var response = _io.ReadString("Do you want instructions"); - if (!response.Equals("no", StringComparison.InvariantCultureIgnoreCase)) + if (!_io.ReadString("Do you want instructions").Equals("no", InvariantCultureIgnoreCase)) { _io.Write(Resource.Streams.Instructions); } + + BuildBugs(); + + _io.Write(Resource.Streams.PlayAgain); + } + + private void BuildBugs() + { + var yourBug = new Bug(); + var myBug = new Bug(); + + while (true) + { + if (TryBuild(yourBug, m => m.You) || TryBuild(myBug, m => m.I)) + { + if (yourBug.IsComplete) { _io.WriteLine(Message.Complete.You); } + if (myBug.IsComplete) { _io.WriteLine(Message.Complete.I); } + + if (!_io.ReadString("Do you want the picture").Equals("no", InvariantCultureIgnoreCase)) + { + _io.WriteLine(yourBug.ToString("Your", 'A')); + _io.WriteLine(myBug.ToString("My", 'F')); + } + } + + if (yourBug.IsComplete || myBug.IsComplete) { break; } + } + } + + private bool TryBuild(Bug bug, Func messageTransform) + { + var roll = _random.Next(6) + 1; + _io.WriteLine(messageTransform(Message.Rolled.ForValue(roll))); + + IPart part = roll switch + { + 1 => new Body(), + 2 => new Neck(), + 3 => new Head(), + 4 => new Feeler(), + 5 => new Tail(), + 6 => new Leg(), + _ => throw new Exception("Unexpected roll value") + }; + _io.WriteLine($"{roll}={part.GetType().Name}"); + + var partAdded = bug.TryAdd(part, out var message); + _io.WriteLine(messageTransform.Invoke(message)); + + return partAdded; } } \ No newline at end of file diff --git a/16_Bug/csharp/Resources/Message.cs b/16_Bug/csharp/Resources/Message.cs index be85faf8..4c719475 100644 --- a/16_Bug/csharp/Resources/Message.cs +++ b/16_Bug/csharp/Resources/Message.cs @@ -24,6 +24,8 @@ internal class Message public static Message LegAdded = new("now have {0} legs"); public static Message LegsFull = new("I have 6 feet.", "You have 6 feet already"); + public static Message Complete = new("bug is finished."); + private Message(string common) : this("I " + common, "You" + common) { @@ -40,5 +42,5 @@ internal class Message public static Message DoNotHaveA(Part part) => new($"do no have a {part.Name}"); - public Message ForQuantity(int quantity) => new(string.Format(I, quantity), string.Format(You, quantity)); + public Message ForValue(int quantity) => new(string.Format(I, quantity), string.Format(You, quantity)); } \ No newline at end of file diff --git a/16_Bug/csharp/Resources/PlayAgain.txt b/16_Bug/csharp/Resources/PlayAgain.txt new file mode 100644 index 00000000..2380e130 --- /dev/null +++ b/16_Bug/csharp/Resources/PlayAgain.txt @@ -0,0 +1 @@ +I hope you enjoyed the game, play it again soon!! diff --git a/16_Bug/csharp/Resources/Resource.cs b/16_Bug/csharp/Resources/Resource.cs index 57f05438..2b34a4e6 100644 --- a/16_Bug/csharp/Resources/Resource.cs +++ b/16_Bug/csharp/Resources/Resource.cs @@ -9,17 +9,11 @@ internal static class Resource { public static Stream Introduction => GetStream(); public static Stream Instructions => GetStream(); - } - - private static string GetString([CallerMemberName] string? name = null) - { - using var stream = GetStream(name); - using var reader = new StreamReader(stream); - return reader.ReadToEnd(); + public static Stream PlayAgain => GetStream(); } private static Stream GetStream([CallerMemberName] string? name = null) => Assembly.GetExecutingAssembly() - .GetManifestResourceStream($"{typeof(Resource).Namespace}.{name}.txt") + .GetManifestResourceStream($"Bug.Resources.{name}.txt") ?? throw new Exception($"Could not find embedded resource stream '{name}'."); } \ No newline at end of file From a648ebf0441fd7aab1b6f8c03386ed6a4a7a3f75 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 13 Jul 2022 08:15:46 +1000 Subject: [PATCH 10/19] Fix adding parts --- 16_Bug/csharp/Parts/ParentPart.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/16_Bug/csharp/Parts/ParentPart.cs b/16_Bug/csharp/Parts/ParentPart.cs index 78a21d6e..1ca6682f 100644 --- a/16_Bug/csharp/Parts/ParentPart.cs +++ b/16_Bug/csharp/Parts/ParentPart.cs @@ -10,7 +10,12 @@ internal abstract class ParentPart : Part } public bool TryAdd(IPart part, out Message message) - => IsPresent ? TryAddCore(part, out message) : ReportDoNotHave(out message); + => (part.GetType() == GetType(), IsPresent) switch + { + (true, _) => TryAdd(out message), + (false, false) => ReportDoNotHave(out message), + _ => TryAddCore(part, out message) + }; protected abstract bool TryAddCore(IPart part, out Message message); From 98344717f7514ea094936889ea9c70539da4e3b3 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Thu, 14 Jul 2022 00:24:10 +1000 Subject: [PATCH 11/19] CSHARP-16 Fix printing bug --- 16_Bug/csharp/Parts/Body.cs | 21 ++++++++++++--------- 16_Bug/csharp/Parts/Head.cs | 19 +++++++++++-------- 16_Bug/csharp/Parts/Neck.cs | 7 +++++-- 16_Bug/csharp/Parts/Tail.cs | 8 +++++++- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/16_Bug/csharp/Parts/Body.cs b/16_Bug/csharp/Parts/Body.cs index 2b7586dc..58f80405 100644 --- a/16_Bug/csharp/Parts/Body.cs +++ b/16_Bug/csharp/Parts/Body.cs @@ -28,14 +28,17 @@ internal class Body : ParentPart public void AppendTo(StringBuilder builder, char feelerCharacter) { - _neck.AppendTo(builder, feelerCharacter); - builder - .AppendLine(" BBBBBBBBBBBB") - .AppendLine(" B B") - .AppendLine(" B B"); - _tail.AppendTo(builder); - builder - .AppendLine(" BBBBBBBBBBBB"); - _legs.AppendTo(builder); + if (IsPresent) + { + _neck.AppendTo(builder, feelerCharacter); + builder + .AppendLine(" BBBBBBBBBBBB") + .AppendLine(" B B") + .AppendLine(" B B"); + _tail.AppendTo(builder); + builder + .AppendLine(" BBBBBBBBBBBB"); + _legs.AppendTo(builder); + } } } diff --git a/16_Bug/csharp/Parts/Head.cs b/16_Bug/csharp/Parts/Head.cs index 3bab7caa..d7135575 100644 --- a/16_Bug/csharp/Parts/Head.cs +++ b/16_Bug/csharp/Parts/Head.cs @@ -23,13 +23,16 @@ internal class Head : ParentPart public void AppendTo(StringBuilder builder, char feelerCharacter) { - _feelers.AppendTo(builder, feelerCharacter); - builder - .AppendLine(" HHHHHHH") - .AppendLine(" H H") - .AppendLine(" H O O H") - .AppendLine(" H H") - .AppendLine(" H V H") - .AppendLine(" HHHHHHH"); + if (IsPresent) + { + _feelers.AppendTo(builder, feelerCharacter); + builder + .AppendLine(" HHHHHHH") + .AppendLine(" H H") + .AppendLine(" H O O H") + .AppendLine(" H H") + .AppendLine(" H V H") + .AppendLine(" HHHHHHH"); + } } } diff --git a/16_Bug/csharp/Parts/Neck.cs b/16_Bug/csharp/Parts/Neck.cs index e8976c1c..23dacfb7 100644 --- a/16_Bug/csharp/Parts/Neck.cs +++ b/16_Bug/csharp/Parts/Neck.cs @@ -24,7 +24,10 @@ internal class Neck : ParentPart public void AppendTo(StringBuilder builder, char feelerCharacter) { - _head.AppendTo(builder, feelerCharacter); - builder.AppendLine(" N N").AppendLine(" N N"); + if (IsPresent) + { + _head.AppendTo(builder, feelerCharacter); + builder.AppendLine(" N N").AppendLine(" N N"); + } } } diff --git a/16_Bug/csharp/Parts/Tail.cs b/16_Bug/csharp/Parts/Tail.cs index 8c450f1d..ebf4b28f 100644 --- a/16_Bug/csharp/Parts/Tail.cs +++ b/16_Bug/csharp/Parts/Tail.cs @@ -10,5 +10,11 @@ internal class Tail : Part { } - public void AppendTo(StringBuilder builder) => builder.AppendLine("TTTTTB B"); + public void AppendTo(StringBuilder builder) + { + if (IsPresent) + { + builder.AppendLine("TTTTTB B"); + } + } } \ No newline at end of file From 6e47d7fbfd8a9a9a8e755fa7533c38744d906b10 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Thu, 14 Jul 2022 00:39:17 +1000 Subject: [PATCH 12/19] Fix game loop and finished message --- 16_Bug/csharp/Game.cs | 11 ++++++++--- 16_Bug/csharp/Parts/PartCollection.cs | 4 ++-- 16_Bug/csharp/Resources/Message.cs | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/16_Bug/csharp/Game.cs b/16_Bug/csharp/Game.cs index 2b5c0711..8ea1cecf 100644 --- a/16_Bug/csharp/Game.cs +++ b/16_Bug/csharp/Game.cs @@ -36,10 +36,15 @@ internal class Game while (true) { - if (TryBuild(yourBug, m => m.You) || TryBuild(myBug, m => m.I)) + var partAdded = TryBuild(yourBug, m => m.You); + Thread.Sleep(500); + _io.WriteLine(); + partAdded |= TryBuild(myBug, m => m.I); + + if (partAdded) { - if (yourBug.IsComplete) { _io.WriteLine(Message.Complete.You); } - if (myBug.IsComplete) { _io.WriteLine(Message.Complete.I); } + if (yourBug.IsComplete) { _io.WriteLine("Your bug is finished."); } + if (myBug.IsComplete) { _io.WriteLine("My bug is finished."); } if (!_io.ReadString("Do you want the picture").Equals("no", InvariantCultureIgnoreCase)) { diff --git a/16_Bug/csharp/Parts/PartCollection.cs b/16_Bug/csharp/Parts/PartCollection.cs index 6e6034de..9a0fd2ee 100644 --- a/16_Bug/csharp/Parts/PartCollection.cs +++ b/16_Bug/csharp/Parts/PartCollection.cs @@ -36,10 +36,10 @@ internal class PartCollection { if (_count == 0) { return; } - builder.Append(' ', offset); - for (var i = 0; i < length; i++) { + builder.Append(' ', offset); + for (var j = 0; j < _count; j++) { builder.Append(character).Append(' '); diff --git a/16_Bug/csharp/Resources/Message.cs b/16_Bug/csharp/Resources/Message.cs index 4c719475..20a59d9a 100644 --- a/16_Bug/csharp/Resources/Message.cs +++ b/16_Bug/csharp/Resources/Message.cs @@ -27,7 +27,7 @@ internal class Message public static Message Complete = new("bug is finished."); private Message(string common) - : this("I " + common, "You" + common) + : this("I " + common, "You " + common) { } @@ -40,7 +40,7 @@ internal class Message public string I { get; } public string You { get; } - public static Message DoNotHaveA(Part part) => new($"do no have a {part.Name}"); + public static Message DoNotHaveA(Part part) => new($"do not have a {part.Name}"); public Message ForValue(int quantity) => new(string.Format(I, quantity), string.Format(You, quantity)); } \ No newline at end of file From 8f09273ab72f5a9296547fac0092f061f35b5500 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Thu, 14 Jul 2022 00:41:36 +1000 Subject: [PATCH 13/19] Add print gap --- 16_Bug/csharp/Game.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/16_Bug/csharp/Game.cs b/16_Bug/csharp/Game.cs index 8ea1cecf..a8989a4c 100644 --- a/16_Bug/csharp/Game.cs +++ b/16_Bug/csharp/Game.cs @@ -48,8 +48,12 @@ internal class Game if (!_io.ReadString("Do you want the picture").Equals("no", InvariantCultureIgnoreCase)) { - _io.WriteLine(yourBug.ToString("Your", 'A')); - _io.WriteLine(myBug.ToString("My", 'F')); + _io.Write(yourBug.ToString("Your", 'A')); + _io.WriteLine(); + _io.WriteLine(); + _io.WriteLine(); + _io.WriteLine(); + _io.Write(myBug.ToString("My", 'F')); } } From 203f930e126a3584f8b5fa98959290299e674795 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 17 Jul 2022 16:48:42 +1000 Subject: [PATCH 14/19] Add resources --- 26_Chomp/csharp/Chomp.csproj | 8 ++++ 26_Chomp/csharp/Resources/Coordinates.txt | 1 + 26_Chomp/csharp/Resources/HereWeGo.txt | 2 + 26_Chomp/csharp/Resources/HowManyColumns.txt | 1 + 26_Chomp/csharp/Resources/HowManyPlayers.txt | 1 + 26_Chomp/csharp/Resources/HowManyRows.txt | 1 + 26_Chomp/csharp/Resources/Introduction.txt | 6 +++ 26_Chomp/csharp/Resources/Player.txt | 2 + 26_Chomp/csharp/Resources/Resource.cs | 42 ++++++++++++++++++++ 26_Chomp/csharp/Resources/Rules.txt | 22 ++++++++++ 26_Chomp/csharp/Resources/TooManyColumns.txt | 1 + 26_Chomp/csharp/Resources/TooManyRows.txt | 1 + 26_Chomp/csharp/Resources/YouLose.txt | 1 + 13 files changed, 89 insertions(+) create mode 100644 26_Chomp/csharp/Resources/Coordinates.txt create mode 100644 26_Chomp/csharp/Resources/HereWeGo.txt create mode 100644 26_Chomp/csharp/Resources/HowManyColumns.txt create mode 100644 26_Chomp/csharp/Resources/HowManyPlayers.txt create mode 100644 26_Chomp/csharp/Resources/HowManyRows.txt create mode 100644 26_Chomp/csharp/Resources/Introduction.txt create mode 100644 26_Chomp/csharp/Resources/Player.txt create mode 100644 26_Chomp/csharp/Resources/Resource.cs create mode 100644 26_Chomp/csharp/Resources/Rules.txt create mode 100644 26_Chomp/csharp/Resources/TooManyColumns.txt create mode 100644 26_Chomp/csharp/Resources/TooManyRows.txt create mode 100644 26_Chomp/csharp/Resources/YouLose.txt diff --git a/26_Chomp/csharp/Chomp.csproj b/26_Chomp/csharp/Chomp.csproj index d3fe4757..3870320c 100644 --- a/26_Chomp/csharp/Chomp.csproj +++ b/26_Chomp/csharp/Chomp.csproj @@ -6,4 +6,12 @@ enable enable + + + + + + + + diff --git a/26_Chomp/csharp/Resources/Coordinates.txt b/26_Chomp/csharp/Resources/Coordinates.txt new file mode 100644 index 00000000..e78dd644 --- /dev/null +++ b/26_Chomp/csharp/Resources/Coordinates.txt @@ -0,0 +1 @@ +Coordinates of Chomp (row, column) \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/HereWeGo.txt b/26_Chomp/csharp/Resources/HereWeGo.txt new file mode 100644 index 00000000..00975d31 --- /dev/null +++ b/26_Chomp/csharp/Resources/HereWeGo.txt @@ -0,0 +1,2 @@ +Here we go... + diff --git a/26_Chomp/csharp/Resources/HowManyColumns.txt b/26_Chomp/csharp/Resources/HowManyColumns.txt new file mode 100644 index 00000000..e323f959 --- /dev/null +++ b/26_Chomp/csharp/Resources/HowManyColumns.txt @@ -0,0 +1 @@ +How many columns \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/HowManyPlayers.txt b/26_Chomp/csharp/Resources/HowManyPlayers.txt new file mode 100644 index 00000000..98ff0ad7 --- /dev/null +++ b/26_Chomp/csharp/Resources/HowManyPlayers.txt @@ -0,0 +1 @@ +How many players \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/HowManyRows.txt b/26_Chomp/csharp/Resources/HowManyRows.txt new file mode 100644 index 00000000..1ad9464e --- /dev/null +++ b/26_Chomp/csharp/Resources/HowManyRows.txt @@ -0,0 +1 @@ +How many rows \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/Introduction.txt b/26_Chomp/csharp/Resources/Introduction.txt new file mode 100644 index 00000000..7c95e7a6 --- /dev/null +++ b/26_Chomp/csharp/Resources/Introduction.txt @@ -0,0 +1,6 @@ + Chomp + Creative Computing Morristown, New Jersey + + + +This is the game of Chomp (Scientific American, Jan 1973) diff --git a/26_Chomp/csharp/Resources/Player.txt b/26_Chomp/csharp/Resources/Player.txt new file mode 100644 index 00000000..60f9ba5e --- /dev/null +++ b/26_Chomp/csharp/Resources/Player.txt @@ -0,0 +1,2 @@ +Player {0} +Player {0} \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/Resource.cs b/26_Chomp/csharp/Resources/Resource.cs new file mode 100644 index 00000000..e1f06e39 --- /dev/null +++ b/26_Chomp/csharp/Resources/Resource.cs @@ -0,0 +1,42 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Chomp.Resources; + +internal static class Resource +{ + internal static class Streams + { + public static Stream HereWeGo => GetStream(); + public static Stream Introduction => GetStream(); + public static Stream Rules => GetStream(); + public static Stream TooManyColumns => GetStream(); + public static Stream TooManyRows => GetStream(); + } + + internal static class Formats + { + public static string Player => GetString(); + public static string YouLose => GetString(); + } + + internal static class Prompts + { + public static string Coordinates => GetString(); + public static string HowManyPlayers => GetString(); + public static string HowManyRows => GetString(); + public static string HowManyColumns => GetString(); + } + + private static string GetString([CallerMemberName] string? name = null) + { + using var stream = GetStream(name); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + + private static Stream GetStream([CallerMemberName] string? name = null) => + Assembly.GetExecutingAssembly().GetManifestResourceStream($"{typeof(Resource).Namespace}.{name}.txt") + ?? throw new Exception($"Could not find embedded resource stream '{name}'."); +} \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/Rules.txt b/26_Chomp/csharp/Resources/Rules.txt new file mode 100644 index 00000000..2fd9177f --- /dev/null +++ b/26_Chomp/csharp/Resources/Rules.txt @@ -0,0 +1,22 @@ +Chomp is for 1 or more players (humans only). + +Here's how a board looks (this one is 5 by 7): + + 1 2 3 4 5 6 7 8 9 + 1 P * * * * * * + 2 * * * * * * * + 3 * * * * * * * + 4 * * * * * * * + 5 * * * * * * * + + +The board is a big cookie - R rows high and C columns +wide. You input R and C at the start. In the upper left +corner of the cookie is a poison square (P). The one who +chomps the poison square loses. To take a chomp, type the +row and column of one of the squares on the cookie. +All of the squares below and to the right of that square +(including that square, too) disappear -- Chomp!! +No fair chomping on squares that have already been chomped, +or that are outside the original dimensions of the cookie. + diff --git a/26_Chomp/csharp/Resources/TooManyColumns.txt b/26_Chomp/csharp/Resources/TooManyColumns.txt new file mode 100644 index 00000000..1e8766a7 --- /dev/null +++ b/26_Chomp/csharp/Resources/TooManyColumns.txt @@ -0,0 +1 @@ +Too many rows (9 is maximum). Now, \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/TooManyRows.txt b/26_Chomp/csharp/Resources/TooManyRows.txt new file mode 100644 index 00000000..1e8766a7 --- /dev/null +++ b/26_Chomp/csharp/Resources/TooManyRows.txt @@ -0,0 +1 @@ +Too many rows (9 is maximum). Now, \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/YouLose.txt b/26_Chomp/csharp/Resources/YouLose.txt new file mode 100644 index 00000000..c6e22300 --- /dev/null +++ b/26_Chomp/csharp/Resources/YouLose.txt @@ -0,0 +1 @@ +You lose, player {0} \ No newline at end of file From 68c7d13c570ab13c636deb71c0053ee051e7010e Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 17 Jul 2022 16:59:53 +1000 Subject: [PATCH 15/19] Add game loop --- 26_Chomp/csharp/Game.cs | 27 +++++++++++++++++++++++++++ 26_Chomp/csharp/Program.cs | 5 +++++ 2 files changed, 32 insertions(+) create mode 100644 26_Chomp/csharp/Game.cs create mode 100644 26_Chomp/csharp/Program.cs diff --git a/26_Chomp/csharp/Game.cs b/26_Chomp/csharp/Game.cs new file mode 100644 index 00000000..943eb95a --- /dev/null +++ b/26_Chomp/csharp/Game.cs @@ -0,0 +1,27 @@ +namespace Chomp; + +internal class Game +{ + private readonly IReadWrite _io; + + public Game(IReadWrite io) + { + _io = io; + } + + internal void Play() + { + _io.Write(Resource.Streams.Introduction); + if (_io.ReadNumber("Do you want the rules (1=Yes, 0=No!)") != 0) + { + _io.Write(Resource.Streams.Rules); + } + + while (true) + { + _io.Write(Resource.Streams.HereWeGo); + + if (_io.ReadNumber("Again (1=Yes, 0=No!)") != 1) { break; } + } + } +} \ No newline at end of file diff --git a/26_Chomp/csharp/Program.cs b/26_Chomp/csharp/Program.cs new file mode 100644 index 00000000..f541259c --- /dev/null +++ b/26_Chomp/csharp/Program.cs @@ -0,0 +1,5 @@ +global using Games.Common.IO; +global using Chomp.Resources; +using Chomp; + +new Game(new ConsoleIO()).Play(); \ No newline at end of file From bbbf5560f40b5bbc89da04b91c0a0ba9cf176fd3 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 17 Jul 2022 17:17:29 +1000 Subject: [PATCH 16/19] Add parameter input --- 26_Chomp/csharp/Game.cs | 5 ++++- 26_Chomp/csharp/IOExtensions.cs | 24 ++++++++++++++++++++++++ 26_Chomp/csharp/Resources/Resource.cs | 7 +++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 26_Chomp/csharp/IOExtensions.cs diff --git a/26_Chomp/csharp/Game.cs b/26_Chomp/csharp/Game.cs index 943eb95a..96ea19b4 100644 --- a/26_Chomp/csharp/Game.cs +++ b/26_Chomp/csharp/Game.cs @@ -17,11 +17,14 @@ internal class Game _io.Write(Resource.Streams.Rules); } + while (true) { _io.Write(Resource.Streams.HereWeGo); + var (playerCount, rowCount, columnCount) = _io.ReadParameters(); + if (_io.ReadNumber("Again (1=Yes, 0=No!)") != 1) { break; } } } -} \ No newline at end of file +} diff --git a/26_Chomp/csharp/IOExtensions.cs b/26_Chomp/csharp/IOExtensions.cs new file mode 100644 index 00000000..c94053a9 --- /dev/null +++ b/26_Chomp/csharp/IOExtensions.cs @@ -0,0 +1,24 @@ +namespace Chomp; + +internal static class IOExtensions +{ + public static (float, int, int) ReadParameters(this IReadWrite io) + => ( + (int)io.ReadNumber(Resource.Prompts.HowManyPlayers), + io.ReadNumberWithMax(Resource.Prompts.HowManyRows, 9, Resource.Strings.TooManyRows), + io.ReadNumberWithMax(Resource.Prompts.HowManyColumns, 9, Resource.Strings.TooManyColumns) + ); + + private static int ReadNumberWithMax(this IReadWrite io, string initialPrompt, int max, string reprompt) + { + var prompt = initialPrompt; + + while (true) + { + var response = io.ReadNumber(prompt); + if (response <= 9) { return (int)response; } + + prompt = $"{reprompt} {initialPrompt.ToLowerInvariant()}"; + } + } +} \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/Resource.cs b/26_Chomp/csharp/Resources/Resource.cs index e1f06e39..efa933dc 100644 --- a/26_Chomp/csharp/Resources/Resource.cs +++ b/26_Chomp/csharp/Resources/Resource.cs @@ -26,6 +26,13 @@ internal static class Resource public static string HowManyPlayers => GetString(); public static string HowManyRows => GetString(); public static string HowManyColumns => GetString(); + public static string TooManyColumns => GetString(); + } + + internal static class Strings + { + public static string TooManyColumns => GetString(); + public static string TooManyRows => GetString(); } private static string GetString([CallerMemberName] string? name = null) From fae67d6a2a6e0a17619b2413faa7b531a4a8fec8 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 17 Jul 2022 18:34:48 +1000 Subject: [PATCH 17/19] Add PlayerNumber --- 26_Chomp/csharp/Cookie.cs | 53 +++++++++++++++++++++++++++ 26_Chomp/csharp/Game.cs | 9 ++++- 26_Chomp/csharp/PlayerNumber.cs | 32 ++++++++++++++++ 26_Chomp/csharp/Resources/NoFair.txt | 1 + 26_Chomp/csharp/Resources/Player.txt | 3 +- 26_Chomp/csharp/Resources/Resource.cs | 3 +- 26_Chomp/csharp/Resources/YouLose.txt | 2 +- 7 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 26_Chomp/csharp/Cookie.cs create mode 100644 26_Chomp/csharp/PlayerNumber.cs create mode 100644 26_Chomp/csharp/Resources/NoFair.txt diff --git a/26_Chomp/csharp/Cookie.cs b/26_Chomp/csharp/Cookie.cs new file mode 100644 index 00000000..3a32c8c3 --- /dev/null +++ b/26_Chomp/csharp/Cookie.cs @@ -0,0 +1,53 @@ +using System.Text; + +namespace Chomp; + +internal class Cookie +{ + private readonly int _rowCount; + private readonly int _columnCount; + private readonly char[][] _bits; + + public Cookie(int rowCount, int columnCount) + { + _rowCount = rowCount; + _columnCount = columnCount; + + // The calls to Math.Max here are to duplicate the original behaviour + // when negative values are given for the row or column count. + _bits = new char[Math.Max(_rowCount, 1)][]; + for (int row = 0; row < _bits.Length; row++) + { + _bits[row] = Enumerable.Repeat('*', Math.Max(_columnCount, 1)).ToArray(); + } + _bits[0][0] = 'P'; + } + + public bool TryChomp(int row, int column) + { + if (row < 1 || row > _rowCount || column < 1 || column > _columnCount || _bits[row - 1][column - 1] == ' ') + { + return false; + } + + for (int r = row; r <= _rowCount; r++) + { + for (int c = column; c <= _columnCount; c++) + { + _bits[r - 1][c - 1] = ' '; + } + } + + return true; + } + + public override string ToString() + { + var builder = new StringBuilder().AppendLine(" 1 2 3 4 5 6 7 8 9"); + for (int row = 1; row <= _bits.Length; row++) + { + builder.Append(' ').Append(row).Append(" ").AppendLine(string.Join(' ', _bits[row - 1])); + } + return builder.ToString(); + } +} \ No newline at end of file diff --git a/26_Chomp/csharp/Game.cs b/26_Chomp/csharp/Game.cs index 96ea19b4..a9219823 100644 --- a/26_Chomp/csharp/Game.cs +++ b/26_Chomp/csharp/Game.cs @@ -17,13 +17,20 @@ internal class Game _io.Write(Resource.Streams.Rules); } - while (true) { _io.Write(Resource.Streams.HereWeGo); var (playerCount, rowCount, columnCount) = _io.ReadParameters(); + var cookie = new Cookie(rowCount, columnCount); + var player = new PlayerNumber(playerCount); + + _io.WriteLine(cookie); + + _io.WriteLine(string.Format(Resource.Formats.Player, player)); + var (row, column) = _io.Read2Numbers(Resource.Prompts.Coordinates); + if (_io.ReadNumber("Again (1=Yes, 0=No!)") != 1) { break; } } } diff --git a/26_Chomp/csharp/PlayerNumber.cs b/26_Chomp/csharp/PlayerNumber.cs new file mode 100644 index 00000000..16138a9b --- /dev/null +++ b/26_Chomp/csharp/PlayerNumber.cs @@ -0,0 +1,32 @@ +namespace Chomp; + +internal class PlayerNumber +{ + private readonly float _playerCount; + private int _counter; + private float _number; + + // The original code does not constrain playerCount to be an integer + public PlayerNumber(float playerCount) + { + _playerCount = playerCount; + _number = 0; + Increment(); + } + + public static PlayerNumber operator ++(PlayerNumber number) => number.Increment(); + + private PlayerNumber Increment() + { + if (_playerCount == 0) { throw new DivideByZeroException(); } + + // The increment logic here is the same as the original program, and exhibits + // interesting behaviour when _playerCount is not an integer. + _counter++; + _number = _counter - (float)Math.Floor(_counter / _playerCount) * _playerCount; + if (_number == 0) { _number = _playerCount; } + return this; + } + + public override string ToString() => (_number >= 0 ? " " : "") + _number.ToString(); +} \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/NoFair.txt b/26_Chomp/csharp/Resources/NoFair.txt new file mode 100644 index 00000000..9fe310eb --- /dev/null +++ b/26_Chomp/csharp/Resources/NoFair.txt @@ -0,0 +1 @@ +No fair. You're trying to chomp on empty space! diff --git a/26_Chomp/csharp/Resources/Player.txt b/26_Chomp/csharp/Resources/Player.txt index 60f9ba5e..f743df3a 100644 --- a/26_Chomp/csharp/Resources/Player.txt +++ b/26_Chomp/csharp/Resources/Player.txt @@ -1,2 +1 @@ -Player {0} -Player {0} \ No newline at end of file +Player{0} \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/Resource.cs b/26_Chomp/csharp/Resources/Resource.cs index efa933dc..d080b1fb 100644 --- a/26_Chomp/csharp/Resources/Resource.cs +++ b/26_Chomp/csharp/Resources/Resource.cs @@ -10,8 +10,7 @@ internal static class Resource public static Stream HereWeGo => GetStream(); public static Stream Introduction => GetStream(); public static Stream Rules => GetStream(); - public static Stream TooManyColumns => GetStream(); - public static Stream TooManyRows => GetStream(); + public static Stream NoFair => GetStream(); } internal static class Formats diff --git a/26_Chomp/csharp/Resources/YouLose.txt b/26_Chomp/csharp/Resources/YouLose.txt index c6e22300..126d8f1e 100644 --- a/26_Chomp/csharp/Resources/YouLose.txt +++ b/26_Chomp/csharp/Resources/YouLose.txt @@ -1 +1 @@ -You lose, player {0} \ No newline at end of file +You lose, player{0} \ No newline at end of file From 2122de9729722c44cc9141bca87445189e852d9e Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 17 Jul 2022 18:46:46 +1000 Subject: [PATCH 18/19] Add inner game loop --- 26_Chomp/csharp/Cookie.cs | 5 +++- 26_Chomp/csharp/Game.cs | 39 ++++++++++++++++++++++----- 26_Chomp/csharp/Resources/YouLose.txt | 2 +- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/26_Chomp/csharp/Cookie.cs b/26_Chomp/csharp/Cookie.cs index 3a32c8c3..725eadfe 100644 --- a/26_Chomp/csharp/Cookie.cs +++ b/26_Chomp/csharp/Cookie.cs @@ -23,13 +23,16 @@ internal class Cookie _bits[0][0] = 'P'; } - public bool TryChomp(int row, int column) + public bool TryChomp(int row, int column, out char chomped) { if (row < 1 || row > _rowCount || column < 1 || column > _columnCount || _bits[row - 1][column - 1] == ' ') { + chomped = default; return false; } + chomped = _bits[row - 1][column - 1]; + for (int r = row; r <= _rowCount; r++) { for (int c = column; c <= _columnCount; c++) diff --git a/26_Chomp/csharp/Game.cs b/26_Chomp/csharp/Game.cs index a9219823..77a8ccd1 100644 --- a/26_Chomp/csharp/Game.cs +++ b/26_Chomp/csharp/Game.cs @@ -23,15 +23,42 @@ internal class Game var (playerCount, rowCount, columnCount) = _io.ReadParameters(); - var cookie = new Cookie(rowCount, columnCount); - var player = new PlayerNumber(playerCount); + var loser = Play(new Cookie(rowCount, columnCount), new PlayerNumber(playerCount)); - _io.WriteLine(cookie); - - _io.WriteLine(string.Format(Resource.Formats.Player, player)); - var (row, column) = _io.Read2Numbers(Resource.Prompts.Coordinates); + _io.WriteLine(string.Format(Resource.Formats.YouLose, loser)); if (_io.ReadNumber("Again (1=Yes, 0=No!)") != 1) { break; } } } + + private PlayerNumber Play(Cookie cookie, PlayerNumber player) + { + while (true) + { + _io.WriteLine(cookie); + + var poisoned = Chomp(cookie, player); + + if (poisoned) { return player; } + + player++; + } + } + + private bool Chomp(Cookie cookie, PlayerNumber player) + { + while (true) + { + _io.WriteLine(string.Format(Resource.Formats.Player, player)); + + var (row, column) = _io.Read2Numbers(Resource.Prompts.Coordinates); + + if (cookie.TryChomp((int)row, (int)column, out char chomped)) + { + return chomped == 'P'; + } + + _io.Write(Resource.Streams.NoFair); + } + } } diff --git a/26_Chomp/csharp/Resources/YouLose.txt b/26_Chomp/csharp/Resources/YouLose.txt index 126d8f1e..1015e271 100644 --- a/26_Chomp/csharp/Resources/YouLose.txt +++ b/26_Chomp/csharp/Resources/YouLose.txt @@ -1 +1 @@ -You lose, player{0} \ No newline at end of file +You lose, player{0} From ed2e2be6acd42b73dbc6de83612f316c73c1eff1 Mon Sep 17 00:00:00 2001 From: Aldrin Misquitta Date: Sun, 24 Jul 2022 11:05:09 +0530 Subject: [PATCH 19/19] Fix typo in 84_Super_Star_Trek/README.md (#780) Fixes #779 --- 84_Super_Star_Trek/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/84_Super_Star_Trek/README.md b/84_Super_Star_Trek/README.md index 1edeb869..07da653f 100644 --- a/84_Super_Star_Trek/README.md +++ b/84_Super_Star_Trek/README.md @@ -72,7 +72,7 @@ The relation between the Historical and Standard nomenclatures is shown in the s - If you don’t zap a Klingon hard enough (relative to his shield strength) you won’t damage him at all. Your sensors will tell the story. - Damage control will let you know when out-of-commission devices have been completely repaired. -9. Your engines will automatically shit down if you should attempt to leave the galaxy, or if you should try to maneuver through a star, or Starbase, or—heaven help you—a Klingon warship. +9. Your engines will automatically shut down if you should attempt to leave the galaxy, or if you should try to maneuver through a star, or Starbase, or—heaven help you—a Klingon warship. 10. In a pinch, or if you should miscalculate slightly, some shield control energy will be automatically diverted to warp engine control (if your shield are operational!).