From 9b471073b0dcd88612c10acbf1a4bfc3f04c6075 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Fri, 21 Oct 2022 21:48:58 +1100 Subject: [PATCH 1/7] CSHARP-53 Create program sturcture --- 53_King/csharp/Game.cs | 28 ++++++++++++ 53_King/csharp/King.csproj | 8 ++++ 53_King/csharp/Program.cs | 6 +++ .../csharp/Resources/Instructions_Prompt.txt | 1 + .../csharp/Resources/Instructions_Text.txt | 17 +++++++ 53_King/csharp/Resources/Resource.cs | 45 +++++++++++++++++++ 53_King/csharp/Resources/Title.txt | 5 +++ 7 files changed, 110 insertions(+) create mode 100644 53_King/csharp/Game.cs create mode 100644 53_King/csharp/Program.cs create mode 100644 53_King/csharp/Resources/Instructions_Prompt.txt create mode 100644 53_King/csharp/Resources/Instructions_Text.txt create mode 100644 53_King/csharp/Resources/Resource.cs create mode 100644 53_King/csharp/Resources/Title.txt diff --git a/53_King/csharp/Game.cs b/53_King/csharp/Game.cs new file mode 100644 index 00000000..d357bdf3 --- /dev/null +++ b/53_King/csharp/Game.cs @@ -0,0 +1,28 @@ +namespace King; + +internal class Game +{ + const int TermOfOffice = 8; + + private readonly IReadWrite _io; + private readonly IRandom _random; + + public Game(IReadWrite io, IRandom random) + { + _io = io; + _random = random; + } + + public void Play() + { + _io.Write(Resource.Title); + + var response = _io.ReadString(Resource.Instructions_Prompt).ToUpper(); + if (!response.StartsWith('N')) + { + _io.Write(Resource.Instructions_Text(TermOfOffice)); + } + + _io.WriteLine(); + } +} \ No newline at end of file diff --git a/53_King/csharp/King.csproj b/53_King/csharp/King.csproj index d3fe4757..3870320c 100644 --- a/53_King/csharp/King.csproj +++ b/53_King/csharp/King.csproj @@ -6,4 +6,12 @@ enable enable + + + + + + + + diff --git a/53_King/csharp/Program.cs b/53_King/csharp/Program.cs new file mode 100644 index 00000000..6eb4c50e --- /dev/null +++ b/53_King/csharp/Program.cs @@ -0,0 +1,6 @@ +global using Games.Common.IO; +global using Games.Common.Randomness; +global using King.Resources; +using King; + +new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); diff --git a/53_King/csharp/Resources/Instructions_Prompt.txt b/53_King/csharp/Resources/Instructions_Prompt.txt new file mode 100644 index 00000000..0d311b60 --- /dev/null +++ b/53_King/csharp/Resources/Instructions_Prompt.txt @@ -0,0 +1 @@ +Do you want instructions \ No newline at end of file diff --git a/53_King/csharp/Resources/Instructions_Text.txt b/53_King/csharp/Resources/Instructions_Text.txt new file mode 100644 index 00000000..c576123b --- /dev/null +++ b/53_King/csharp/Resources/Instructions_Text.txt @@ -0,0 +1,17 @@ + + + +Congratulations! You've just been elected Premier of Setats +Detinu, a small communist island 30 by 70 miles long. Your +job is to decide upon the country's budget and distribute +money to your countrymen from the communal treasury. +The money system is rallods, and each person needs 100 +rallods per year to survive. Your country's income comes +from farm produce and tourists visiting your magnificent +forests, hunting, fishing, etc. Half your land if farm land +which also has an excellent mineral content and may be sold +to foreign industry (strip mining) who import and support +their own workers. Crops cost between 10 and 15 rallods per +square mile to plant. +Your goal is to complete your {0} year term of office. +Good luck! diff --git a/53_King/csharp/Resources/Resource.cs b/53_King/csharp/Resources/Resource.cs new file mode 100644 index 00000000..f8ddfd3f --- /dev/null +++ b/53_King/csharp/Resources/Resource.cs @@ -0,0 +1,45 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace King.Resources; + +internal static class Resource +{ + public static Stream Title => GetStream(); + + public static string Instructions_Prompt => GetString(); + public static string Instructions_Text(int years) => string.Format(GetString(), years); + + internal static class Formats + { + public static string Player => GetString(); + public static string YouLose => GetString(); + } + + internal static class Prompts + { + public static string WantInstructions => GetString(); + 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) + { + 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/53_King/csharp/Resources/Title.txt b/53_King/csharp/Resources/Title.txt new file mode 100644 index 00000000..f9f7854d --- /dev/null +++ b/53_King/csharp/Resources/Title.txt @@ -0,0 +1,5 @@ + King + Creative Computing Morristown, New Jersey + + + From da0f2d13ab444be03485c4d53b57d21257c27356 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sat, 22 Oct 2022 15:46:44 +1100 Subject: [PATCH 2/7] Add reign initizalization --- 53_King/csharp/Country.cs | 34 +++++++++++++++ 53_King/csharp/Game.cs | 26 +++++++++-- 53_King/csharp/IOExtensions.cs | 43 +++++++++++++++++++ 53_King/csharp/Reign.cs | 23 ++++++++++ ...ions_Prompt.txt => InstructionsPrompt.txt} | 0 ...ructions_Text.txt => InstructionsText.txt} | 0 53_King/csharp/Resources/Resource.cs | 12 +++++- .../Resources/SavedCountrymenPrompt.txt | 1 + 53_King/csharp/Resources/SavedLandError.txt | 2 + 53_King/csharp/Resources/SavedLandPrompt.txt | 1 + .../csharp/Resources/SavedTreasuryPrompt.txt | 1 + .../csharp/Resources/SavedWorkersPrompt.txt | 1 + 53_King/csharp/Resources/SavedYearsError.txt | 1 + 53_King/csharp/Resources/SavedYearsPrompt.txt | 1 + 14 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 53_King/csharp/Country.cs create mode 100644 53_King/csharp/IOExtensions.cs create mode 100644 53_King/csharp/Reign.cs rename 53_King/csharp/Resources/{Instructions_Prompt.txt => InstructionsPrompt.txt} (100%) rename 53_King/csharp/Resources/{Instructions_Text.txt => InstructionsText.txt} (100%) create mode 100644 53_King/csharp/Resources/SavedCountrymenPrompt.txt create mode 100644 53_King/csharp/Resources/SavedLandError.txt create mode 100644 53_King/csharp/Resources/SavedLandPrompt.txt create mode 100644 53_King/csharp/Resources/SavedTreasuryPrompt.txt create mode 100644 53_King/csharp/Resources/SavedWorkersPrompt.txt create mode 100644 53_King/csharp/Resources/SavedYearsError.txt create mode 100644 53_King/csharp/Resources/SavedYearsPrompt.txt diff --git a/53_King/csharp/Country.cs b/53_King/csharp/Country.cs new file mode 100644 index 00000000..1e94e821 --- /dev/null +++ b/53_King/csharp/Country.cs @@ -0,0 +1,34 @@ +namespace King; + +internal class Country +{ + private readonly IRandom _random; + private float _rallods; + private float _countrymen; + private float _foreigners; + private float _land; + private float _plantingCost; + private float _landValue; + + public Country(IRandom random) + : this( + random, + (int)(60000 + random.NextFloat(1000) - random.NextFloat(1000)), + (int)(500 + random.NextFloat(10) - random.NextFloat(10)), + 0, + 2000) + { + } + + public Country(IRandom random, float rallods, float countrymen, float foreigners, float land) + { + _random = random; + _rallods = rallods; + _countrymen = countrymen; + _foreigners = foreigners; + _land = land; + + _plantingCost = random.Next(10, 15); + _landValue = random.Next(95, 105); + } +} diff --git a/53_King/csharp/Game.cs b/53_King/csharp/Game.cs index d357bdf3..c8a44a8c 100644 --- a/53_King/csharp/Game.cs +++ b/53_King/csharp/Game.cs @@ -17,12 +17,30 @@ internal class Game { _io.Write(Resource.Title); - var response = _io.ReadString(Resource.Instructions_Prompt).ToUpper(); - if (!response.StartsWith('N')) + if (SetUpReign() is Reign reign) { - _io.Write(Resource.Instructions_Text(TermOfOffice)); + _io.Write(reign); } _io.WriteLine(); + _io.WriteLine(); } -} \ No newline at end of file + + private Reign? SetUpReign() + { + var response = _io.ReadString(Resource.InstructionsPrompt).ToUpper(); + + if (response.Equals("Again", StringComparison.InvariantCultureIgnoreCase)) + { + return _io.TryReadGameData(_random, out var reign) ? reign : null; + } + + if (!response.StartsWith("N", StringComparison.InvariantCultureIgnoreCase)) + { + _io.Write(Resource.InstructionsText(TermOfOffice)); + } + + _io.WriteLine(); + return new Reign(_io, _random); + } +} diff --git a/53_King/csharp/IOExtensions.cs b/53_King/csharp/IOExtensions.cs new file mode 100644 index 00000000..183621ca --- /dev/null +++ b/53_King/csharp/IOExtensions.cs @@ -0,0 +1,43 @@ +using System.Diagnostics.CodeAnalysis; +using static King.Resources.Resource; + +namespace King; + +internal static class IOExtensions +{ + internal static bool TryReadGameData(this IReadWrite io, IRandom random, [NotNullWhen(true)] out Reign? reign) + { + if (io.TryReadValue(SavedYearsPrompt, v => v < Reign.MaxTerm, SavedYearsError(Reign.MaxTerm), out var years) && + io.TryReadValue(SavedTreasuryPrompt, out var rallods) && + io.TryReadValue(SavedCountrymenPrompt, out var countrymen) && + io.TryReadValue(SavedWorkersPrompt, out var workers) && + io.TryReadValue(SavedLandPrompt, v => v is > 1000 and <= 2000, SavedLandError, out var land)) + { + reign = new Reign(io, new Country(random, rallods, countrymen, workers, land), years + 1); + return true; + } + + reign = default; + return false; + } + + private static bool TryReadValue(this IReadWrite io, string prompt, out float value) + => io.TryReadValue(prompt, _ => true, "", out value); + + private static bool TryReadValue( + this IReadWrite io, + string prompt, + Predicate isValid, + string error, + out float value) + { + while (true) + { + value = io.ReadNumber(prompt); + if (value < 0) { return false; } + if (isValid(value)) { return true; } + + io.Write(error); + } + } +} \ No newline at end of file diff --git a/53_King/csharp/Reign.cs b/53_King/csharp/Reign.cs new file mode 100644 index 00000000..4e6c45c5 --- /dev/null +++ b/53_King/csharp/Reign.cs @@ -0,0 +1,23 @@ +namespace King; + +internal class Reign +{ + public const int MaxTerm = 8; + + private readonly IReadWrite _io; + private readonly Country _country; + private readonly float _year; + + public Reign(IReadWrite io, IRandom random) + : this(io, new Country(random), 0) + { + + } + + public Reign(IReadWrite io, Country country, float year) + { + _io = io; + _country = country; + _year = year; + } +} diff --git a/53_King/csharp/Resources/Instructions_Prompt.txt b/53_King/csharp/Resources/InstructionsPrompt.txt similarity index 100% rename from 53_King/csharp/Resources/Instructions_Prompt.txt rename to 53_King/csharp/Resources/InstructionsPrompt.txt diff --git a/53_King/csharp/Resources/Instructions_Text.txt b/53_King/csharp/Resources/InstructionsText.txt similarity index 100% rename from 53_King/csharp/Resources/Instructions_Text.txt rename to 53_King/csharp/Resources/InstructionsText.txt diff --git a/53_King/csharp/Resources/Resource.cs b/53_King/csharp/Resources/Resource.cs index f8ddfd3f..6626a3dd 100644 --- a/53_King/csharp/Resources/Resource.cs +++ b/53_King/csharp/Resources/Resource.cs @@ -7,9 +7,17 @@ internal static class Resource { public static Stream Title => GetStream(); - public static string Instructions_Prompt => GetString(); - public static string Instructions_Text(int years) => string.Format(GetString(), years); + public static string InstructionsPrompt => GetString(); + public static string InstructionsText(int years) => string.Format(GetString(), years); + public static string SavedYearsPrompt => GetString(); + public static string SavedYearsError(int years) => string.Format(GetString(), years); + public static string SavedTreasuryPrompt => GetString(); + public static string SavedCountrymenPrompt => GetString(); + public static string SavedWorkersPrompt => GetString(); + public static string SavedLandPrompt => GetString(); + public static string SavedLandError => GetString(); + internal static class Formats { public static string Player => GetString(); diff --git a/53_King/csharp/Resources/SavedCountrymenPrompt.txt b/53_King/csharp/Resources/SavedCountrymenPrompt.txt new file mode 100644 index 00000000..120718d2 --- /dev/null +++ b/53_King/csharp/Resources/SavedCountrymenPrompt.txt @@ -0,0 +1 @@ +How many countrymen \ No newline at end of file diff --git a/53_King/csharp/Resources/SavedLandError.txt b/53_King/csharp/Resources/SavedLandError.txt new file mode 100644 index 00000000..9ac66dad --- /dev/null +++ b/53_King/csharp/Resources/SavedLandError.txt @@ -0,0 +1,2 @@ + Come on, you started with 1000 sq. miles of farm land + and 10,000 sq. miles of forest land diff --git a/53_King/csharp/Resources/SavedLandPrompt.txt b/53_King/csharp/Resources/SavedLandPrompt.txt new file mode 100644 index 00000000..e8afdf72 --- /dev/null +++ b/53_King/csharp/Resources/SavedLandPrompt.txt @@ -0,0 +1 @@ +How many square miles of land \ No newline at end of file diff --git a/53_King/csharp/Resources/SavedTreasuryPrompt.txt b/53_King/csharp/Resources/SavedTreasuryPrompt.txt new file mode 100644 index 00000000..f4a50f58 --- /dev/null +++ b/53_King/csharp/Resources/SavedTreasuryPrompt.txt @@ -0,0 +1 @@ +How much did you have in the treasury \ No newline at end of file diff --git a/53_King/csharp/Resources/SavedWorkersPrompt.txt b/53_King/csharp/Resources/SavedWorkersPrompt.txt new file mode 100644 index 00000000..b88a9c10 --- /dev/null +++ b/53_King/csharp/Resources/SavedWorkersPrompt.txt @@ -0,0 +1 @@ +How many workers \ No newline at end of file diff --git a/53_King/csharp/Resources/SavedYearsError.txt b/53_King/csharp/Resources/SavedYearsError.txt new file mode 100644 index 00000000..1c8c3c99 --- /dev/null +++ b/53_King/csharp/Resources/SavedYearsError.txt @@ -0,0 +1 @@ + Come on, your term in office is only {0} years. diff --git a/53_King/csharp/Resources/SavedYearsPrompt.txt b/53_King/csharp/Resources/SavedYearsPrompt.txt new file mode 100644 index 00000000..afbda229 --- /dev/null +++ b/53_King/csharp/Resources/SavedYearsPrompt.txt @@ -0,0 +1 @@ +How many years had you been in office when interrupted \ No newline at end of file From d4c5fb1df754931e27c3486b4527b1e01f31348c Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 1 Nov 2022 17:47:28 +1100 Subject: [PATCH 3/7] Add player input routines --- 53_King/csharp/Country.cs | 71 ++++++++++++++++++- 53_King/csharp/Game.cs | 2 +- 53_King/csharp/IOExtensions.cs | 28 ++++++-- 53_King/csharp/Program.cs | 1 + 53_King/csharp/Reign.cs | 14 +++- 53_King/csharp/Resources/GiveRallodsError.txt | 1 + .../csharp/Resources/GiveRallodsPrompt.txt | 1 + 53_King/csharp/Resources/PlantLandError1.txt | 1 + 53_King/csharp/Resources/PlantLandError2.txt | 1 + 53_King/csharp/Resources/PlantLandError3.txt | 1 + 53_King/csharp/Resources/PlantLandPrompt.txt | 1 + 53_King/csharp/Resources/PollutionError.txt | 1 + 53_King/csharp/Resources/PollutionPrompt.txt | 1 + 53_King/csharp/Resources/Resource.cs | 62 ++++++++++------ 53_King/csharp/Resources/SellLandError.txt | 2 + .../csharp/Resources/SellLandErrorReason.txt | 4 ++ 53_King/csharp/Resources/SellLandPrompt.txt | 1 + .../csharp/Resources/StatusSansWorkers.txt | 6 ++ .../csharp/Resources/StatusWithWorkers.txt | 6 ++ 53_King/csharp/ValidityTest.cs | 26 +++++++ 53_King/king.bas | 1 + 21 files changed, 201 insertions(+), 31 deletions(-) create mode 100644 53_King/csharp/Resources/GiveRallodsError.txt create mode 100644 53_King/csharp/Resources/GiveRallodsPrompt.txt create mode 100644 53_King/csharp/Resources/PlantLandError1.txt create mode 100644 53_King/csharp/Resources/PlantLandError2.txt create mode 100644 53_King/csharp/Resources/PlantLandError3.txt create mode 100644 53_King/csharp/Resources/PlantLandPrompt.txt create mode 100644 53_King/csharp/Resources/PollutionError.txt create mode 100644 53_King/csharp/Resources/PollutionPrompt.txt create mode 100644 53_King/csharp/Resources/SellLandError.txt create mode 100644 53_King/csharp/Resources/SellLandErrorReason.txt create mode 100644 53_King/csharp/Resources/SellLandPrompt.txt create mode 100644 53_King/csharp/Resources/StatusSansWorkers.txt create mode 100644 53_King/csharp/Resources/StatusWithWorkers.txt create mode 100644 53_King/csharp/ValidityTest.cs diff --git a/53_King/csharp/Country.cs b/53_King/csharp/Country.cs index 1e94e821..5b47c50a 100644 --- a/53_King/csharp/Country.cs +++ b/53_King/csharp/Country.cs @@ -2,6 +2,7 @@ namespace King; internal class Country { + private readonly IReadWrite _io; private readonly IRandom _random; private float _rallods; private float _countrymen; @@ -10,8 +11,9 @@ internal class Country private float _plantingCost; private float _landValue; - public Country(IRandom random) + public Country(IReadWrite io, IRandom random) : this( + io, random, (int)(60000 + random.NextFloat(1000) - random.NextFloat(1000)), (int)(500 + random.NextFloat(10) - random.NextFloat(10)), @@ -20,8 +22,9 @@ internal class Country { } - public Country(IRandom random, float rallods, float countrymen, float foreigners, float land) + public Country(IReadWrite io, IRandom random, float rallods, float countrymen, float foreigners, float land) { + _io = io; _random = random; _rallods = rallods; _countrymen = countrymen; @@ -31,4 +34,68 @@ internal class Country _plantingCost = random.Next(10, 15); _landValue = random.Next(95, 105); } + + public string Status => Resource.Status(_rallods, _countrymen, _foreigners, _land, _landValue, _plantingCost); + private float FarmLand => _land - 1000; + + public bool SellLand() + { + if (_io.TryReadValue( + SellLandPrompt, + out var landSold, + new ValidityTest(v => v <= FarmLand, () => SellLandError(FarmLand)))) + { + _land = (int)(_land - landSold); + _rallods = (int)(_rallods + landSold * _landValue); + return true; + } + + return false; + } + + public bool DistributeRallods() + { + if (_io.TryReadValue( + GiveRallodsPrompt, + out var rallodsGiven, + new ValidityTest(v => v <= _rallods, () => GiveRallodsError(_rallods)))) + { + _rallods = (int)(_rallods - rallodsGiven); + return true; + } + + return false; + } + + public bool PlantLand() + { + if (_rallods > 0 && + _io.TryReadValue( + PlantLandPrompt, + out var landPlanted, + new ValidityTest(v => v <= _countrymen * 2, PlantLandError1), + new ValidityTest(v => v <= FarmLand, PlantLandError2(FarmLand)), + new ValidityTest(v => v * _plantingCost <= _rallods, PlantLandError3(_rallods)))) + { + _rallods -= (int)(landPlanted * _plantingCost); + return true; + } + + return false; + } + + public bool ControlPollution() + { + if (_rallods > 0 && + _io.TryReadValue( + PollutionPrompt, + out var rallodsGiven, + new ValidityTest(v => v <= _rallods, () => PollutionError(_rallods)))) + { + _rallods = (int)(_rallods - rallodsGiven); + return true; + } + + return false; + } } diff --git a/53_King/csharp/Game.cs b/53_King/csharp/Game.cs index c8a44a8c..198ff14f 100644 --- a/53_King/csharp/Game.cs +++ b/53_King/csharp/Game.cs @@ -19,7 +19,7 @@ internal class Game if (SetUpReign() is Reign reign) { - _io.Write(reign); + reign.PlayYear(); } _io.WriteLine(); diff --git a/53_King/csharp/IOExtensions.cs b/53_King/csharp/IOExtensions.cs index 183621ca..c2707c0d 100644 --- a/53_King/csharp/IOExtensions.cs +++ b/53_King/csharp/IOExtensions.cs @@ -13,7 +13,7 @@ internal static class IOExtensions io.TryReadValue(SavedWorkersPrompt, out var workers) && io.TryReadValue(SavedLandPrompt, v => v is > 1000 and <= 2000, SavedLandError, out var land)) { - reign = new Reign(io, new Country(random, rallods, countrymen, workers, land), years + 1); + reign = new Reign(io, new Country(io, random, rallods, countrymen, workers, land), years + 1); return true; } @@ -21,15 +21,33 @@ internal static class IOExtensions return false; } - private static bool TryReadValue(this IReadWrite io, string prompt, out float value) + internal static bool TryReadValue(this IReadWrite io, string prompt, out float value, params ValidityTest[] tests) + { + while (true) + { + var response = value = io.ReadNumber(prompt); + if (response < 0) { return false; } + if (tests.All(test => test.IsValid(response, io))) { return true; } + } + } + + internal static bool TryReadValue(this IReadWrite io, string prompt, out float value) => io.TryReadValue(prompt, _ => true, "", out value); - private static bool TryReadValue( + internal static bool TryReadValue( this IReadWrite io, string prompt, Predicate isValid, string error, out float value) + => io.TryReadValue(prompt, isValid, () => error, out value); + + internal static bool TryReadValue( + this IReadWrite io, + string prompt, + Predicate isValid, + Func getError, + out float value) { while (true) { @@ -37,7 +55,7 @@ internal static class IOExtensions if (value < 0) { return false; } if (isValid(value)) { return true; } - io.Write(error); + io.Write(getError()); } } -} \ No newline at end of file +} diff --git a/53_King/csharp/Program.cs b/53_King/csharp/Program.cs index 6eb4c50e..5aae4ccb 100644 --- a/53_King/csharp/Program.cs +++ b/53_King/csharp/Program.cs @@ -1,6 +1,7 @@ global using Games.Common.IO; global using Games.Common.Randomness; global using King.Resources; +global using static King.Resources.Resource; using King; new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); diff --git a/53_King/csharp/Reign.cs b/53_King/csharp/Reign.cs index 4e6c45c5..58e89b66 100644 --- a/53_King/csharp/Reign.cs +++ b/53_King/csharp/Reign.cs @@ -9,9 +9,8 @@ internal class Reign private readonly float _year; public Reign(IReadWrite io, IRandom random) - : this(io, new Country(random), 0) + : this(io, new Country(io, random), 0) { - } public Reign(IReadWrite io, Country country, float year) @@ -20,4 +19,15 @@ internal class Reign _country = country; _year = year; } + + public void PlayYear() + { + _io.Write(_country.Status); + + var playerSoldLand = _country.SellLand(); + var playerDistributedRallods = _country.DistributeRallods(); + var playerPlantedLand = _country.PlantLand(); + var playerControlledPollution = _country.ControlPollution(); + + } } diff --git a/53_King/csharp/Resources/GiveRallodsError.txt b/53_King/csharp/Resources/GiveRallodsError.txt new file mode 100644 index 00000000..df0d7cc0 --- /dev/null +++ b/53_King/csharp/Resources/GiveRallodsError.txt @@ -0,0 +1 @@ + Think again. You've only got {0} rallods in the treasury. diff --git a/53_King/csharp/Resources/GiveRallodsPrompt.txt b/53_King/csharp/Resources/GiveRallodsPrompt.txt new file mode 100644 index 00000000..e8bd345b --- /dev/null +++ b/53_King/csharp/Resources/GiveRallodsPrompt.txt @@ -0,0 +1 @@ +How many rallods will you distribute among your countrymen \ No newline at end of file diff --git a/53_King/csharp/Resources/PlantLandError1.txt b/53_King/csharp/Resources/PlantLandError1.txt new file mode 100644 index 00000000..ef959f9f --- /dev/null +++ b/53_King/csharp/Resources/PlantLandError1.txt @@ -0,0 +1 @@ + Sorry, but each countryman can only plant 2 sq. miles. \ No newline at end of file diff --git a/53_King/csharp/Resources/PlantLandError2.txt b/53_King/csharp/Resources/PlantLandError2.txt new file mode 100644 index 00000000..e5844aa1 --- /dev/null +++ b/53_King/csharp/Resources/PlantLandError2.txt @@ -0,0 +1 @@ + Sorry, but you've only {0} sq. miles of farm land. \ No newline at end of file diff --git a/53_King/csharp/Resources/PlantLandError3.txt b/53_King/csharp/Resources/PlantLandError3.txt new file mode 100644 index 00000000..38264442 --- /dev/null +++ b/53_King/csharp/Resources/PlantLandError3.txt @@ -0,0 +1 @@ + Think again, You've only {0} rallods left in the treasury. diff --git a/53_King/csharp/Resources/PlantLandPrompt.txt b/53_King/csharp/Resources/PlantLandPrompt.txt new file mode 100644 index 00000000..f2fe448e --- /dev/null +++ b/53_King/csharp/Resources/PlantLandPrompt.txt @@ -0,0 +1 @@ +How many square miles do you wish to plant \ No newline at end of file diff --git a/53_King/csharp/Resources/PollutionError.txt b/53_King/csharp/Resources/PollutionError.txt new file mode 100644 index 00000000..f99644e3 --- /dev/null +++ b/53_King/csharp/Resources/PollutionError.txt @@ -0,0 +1 @@ + Think again. You only have {0} rallods remaining. diff --git a/53_King/csharp/Resources/PollutionPrompt.txt b/53_King/csharp/Resources/PollutionPrompt.txt new file mode 100644 index 00000000..252fb333 --- /dev/null +++ b/53_King/csharp/Resources/PollutionPrompt.txt @@ -0,0 +1 @@ +How many rallods do you wish to spend on pollution control \ No newline at end of file diff --git a/53_King/csharp/Resources/Resource.cs b/53_King/csharp/Resources/Resource.cs index 6626a3dd..37ff09eb 100644 --- a/53_King/csharp/Resources/Resource.cs +++ b/53_King/csharp/Resources/Resource.cs @@ -5,11 +5,52 @@ namespace King.Resources; internal static class Resource { + private static bool _sellLandErrorShown; + public static Stream Title => GetStream(); public static string InstructionsPrompt => GetString(); public static string InstructionsText(int years) => string.Format(GetString(), years); + public static string Status( + float rallods, + float countrymen, + float workers, + float land, + float landValue, + float plantingCost) + => string.Format( + workers == 0 ? StatusWithWorkers : StatusSansWorkers, + rallods, + (int)countrymen, + (int)workers, + (int)land, + landValue, + plantingCost); + + private static string StatusWithWorkers => GetString(); + private static string StatusSansWorkers => GetString(); + + public static string SellLandPrompt => GetString(); + public static string SellLandError(float farmLand) + { + var error = string.Format(GetString(), farmLand, _sellLandErrorShown ? "" : SellLandErrorReason); + _sellLandErrorShown = true; + return error; + } + private static string SellLandErrorReason => GetString(); + + public static string GiveRallodsPrompt => GetString(); + public static string GiveRallodsError(float rallods) => string.Format(GetString(), rallods); + + public static string PlantLandPrompt => GetString(); + public static string PlantLandError1 => GetString(); + public static string PlantLandError2(float farmLand) => string.Format(GetString(), farmLand); + public static string PlantLandError3(float rallods) => string.Format(GetString(), rallods); + + public static string PollutionPrompt => GetString(); + public static string PollutionError(float rallods) => string.Format(GetString(), rallods); + public static string SavedYearsPrompt => GetString(); public static string SavedYearsError(int years) => string.Format(GetString(), years); public static string SavedTreasuryPrompt => GetString(); @@ -17,27 +58,6 @@ internal static class Resource public static string SavedWorkersPrompt => GetString(); public static string SavedLandPrompt => GetString(); public static string SavedLandError => GetString(); - - internal static class Formats - { - public static string Player => GetString(); - public static string YouLose => GetString(); - } - - internal static class Prompts - { - public static string WantInstructions => GetString(); - 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) { diff --git a/53_King/csharp/Resources/SellLandError.txt b/53_King/csharp/Resources/SellLandError.txt new file mode 100644 index 00000000..83e0266c --- /dev/null +++ b/53_King/csharp/Resources/SellLandError.txt @@ -0,0 +1,2 @@ +*** Think again. You only have {0} square miles of farm land. +{1} \ No newline at end of file diff --git a/53_King/csharp/Resources/SellLandErrorReason.txt b/53_King/csharp/Resources/SellLandErrorReason.txt new file mode 100644 index 00000000..836352bb --- /dev/null +++ b/53_King/csharp/Resources/SellLandErrorReason.txt @@ -0,0 +1,4 @@ + +(Foreign industry will only buy farm land because +forest land is uneconomical to strip mine due to trees, +thicker top soil, etc.) diff --git a/53_King/csharp/Resources/SellLandPrompt.txt b/53_King/csharp/Resources/SellLandPrompt.txt new file mode 100644 index 00000000..8d01c2c2 --- /dev/null +++ b/53_King/csharp/Resources/SellLandPrompt.txt @@ -0,0 +1 @@ +How many square miles do you wish to sell to industry \ No newline at end of file diff --git a/53_King/csharp/Resources/StatusSansWorkers.txt b/53_King/csharp/Resources/StatusSansWorkers.txt new file mode 100644 index 00000000..7efb84e7 --- /dev/null +++ b/53_King/csharp/Resources/StatusSansWorkers.txt @@ -0,0 +1,6 @@ + +You now have {0} rallods in the treasury. + {1} countrymen, and {3} sq. miles of land. +This year industry will buy land for {4} rallods per square mile. +Land currently costs {5} rallods per square mile to plant. + diff --git a/53_King/csharp/Resources/StatusWithWorkers.txt b/53_King/csharp/Resources/StatusWithWorkers.txt new file mode 100644 index 00000000..e7bc5c4a --- /dev/null +++ b/53_King/csharp/Resources/StatusWithWorkers.txt @@ -0,0 +1,6 @@ + +You now have {0} rallods in the treasury. + {1} countrymen, {2} foreign workers and {3} sq. miles of land. +This year industry will buy land for {4} rallods per square mile. +Land currently costs {5} rallods per square mile to plant. + diff --git a/53_King/csharp/ValidityTest.cs b/53_King/csharp/ValidityTest.cs new file mode 100644 index 00000000..f1aeb5ec --- /dev/null +++ b/53_King/csharp/ValidityTest.cs @@ -0,0 +1,26 @@ +namespace King; + +internal class ValidityTest +{ + private readonly Predicate _isValid; + private readonly Func _getError; + + public ValidityTest(Predicate isValid, string error) + : this(isValid, () => error) + { + } + + public ValidityTest(Predicate isValid, Func getError) + { + _isValid = isValid; + _getError = getError; + } + + public bool IsValid(float value, IReadWrite io) + { + if (_isValid(value)) { return true; } + + io.Write(_getError()); + return false; + } +} \ No newline at end of file diff --git a/53_King/king.bas b/53_King/king.bas index 7352fa58..5e9ae163 100644 --- a/53_King/king.bas +++ b/53_King/king.bas @@ -99,6 +99,7 @@ 1000 GOTO 600 1002 PRINT 1003 PRINT +1005 PRINT A 1010 A=INT(A-K) 1020 A4=A 1100 IF INT(I/100-B)>=0 THEN 1120 From ab7f2c11827160348eab05162e5191734a1d10a8 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 2 Nov 2022 08:00:27 +1100 Subject: [PATCH 4/7] Add game loop and end --- 53_King/csharp/Game.cs | 5 +++-- 53_King/csharp/IOExtensions.cs | 2 +- 53_King/csharp/Reign.cs | 18 ++++++++++++++---- 53_King/csharp/Resources/Goodbye.txt | 5 +++++ 53_King/csharp/Resources/Resource.cs | 2 ++ 5 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 53_King/csharp/Resources/Goodbye.txt diff --git a/53_King/csharp/Game.cs b/53_King/csharp/Game.cs index 198ff14f..92d8063f 100644 --- a/53_King/csharp/Game.cs +++ b/53_King/csharp/Game.cs @@ -17,9 +17,10 @@ internal class Game { _io.Write(Resource.Title); - if (SetUpReign() is Reign reign) + var reign = SetUpReign(); + if (reign != null) { - reign.PlayYear(); + while (reign.PlayYear()); } _io.WriteLine(); diff --git a/53_King/csharp/IOExtensions.cs b/53_King/csharp/IOExtensions.cs index c2707c0d..e59bf4c0 100644 --- a/53_King/csharp/IOExtensions.cs +++ b/53_King/csharp/IOExtensions.cs @@ -26,7 +26,7 @@ internal static class IOExtensions while (true) { var response = value = io.ReadNumber(prompt); - if (response < 0) { return false; } + if (response == 0) { return false; } if (tests.All(test => test.IsValid(response, io))) { return true; } } } diff --git a/53_King/csharp/Reign.cs b/53_King/csharp/Reign.cs index 58e89b66..2bdc9b89 100644 --- a/53_King/csharp/Reign.cs +++ b/53_King/csharp/Reign.cs @@ -6,10 +6,10 @@ internal class Reign private readonly IReadWrite _io; private readonly Country _country; - private readonly float _year; + private float _year; public Reign(IReadWrite io, IRandom random) - : this(io, new Country(io, random), 0) + : this(io, new Country(io, random), 1) { } @@ -20,7 +20,7 @@ internal class Reign _year = year; } - public void PlayYear() + public bool PlayYear() { _io.Write(_country.Status); @@ -28,6 +28,16 @@ internal class Reign var playerDistributedRallods = _country.DistributeRallods(); var playerPlantedLand = _country.PlantLand(); var playerControlledPollution = _country.ControlPollution(); - + + if (playerSoldLand || playerDistributedRallods || playerPlantedLand || playerControlledPollution) + { + _year++; + return true; + } + else + { + _io.Write(Goodbye); + return false; + } } } diff --git a/53_King/csharp/Resources/Goodbye.txt b/53_King/csharp/Resources/Goodbye.txt new file mode 100644 index 00000000..325890a5 --- /dev/null +++ b/53_King/csharp/Resources/Goodbye.txt @@ -0,0 +1,5 @@ + +Goodbye. +(If you wish to continue this game at a later date, answer +'again' when asked if you want instructions at the start +of the game). diff --git a/53_King/csharp/Resources/Resource.cs b/53_King/csharp/Resources/Resource.cs index 37ff09eb..cf555583 100644 --- a/53_King/csharp/Resources/Resource.cs +++ b/53_King/csharp/Resources/Resource.cs @@ -59,6 +59,8 @@ internal static class Resource public static string SavedLandPrompt => GetString(); public static string SavedLandError => GetString(); + public static string Goodbye => GetString(); + private static string GetString([CallerMemberName] string? name = null) { using var stream = GetStream(name); From 9d8a4fbc93c1cdfa4fda0b9afbdfc1ad6239952c Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 29 Nov 2022 22:40:34 +1100 Subject: [PATCH 5/7] Add evaluation of deaths --- 53_King/csharp/Country.cs | 71 ++++++++------ 53_King/csharp/IOExtensions.cs | 2 +- 53_King/csharp/Reign.cs | 25 ++--- 53_King/csharp/Resources/DeathsPollution.txt | 1 + 53_King/csharp/Resources/DeathsStarvation.txt | 1 + 53_King/csharp/Resources/EndAlso.txt | 3 + .../csharp/Resources/EndCongratulations.txt | 10 ++ 53_King/csharp/Resources/EndConsequences.txt | 3 + .../csharp/Resources/EndForeignWorkers.txt | 7 ++ 53_King/csharp/Resources/EndManyDead.txt | 5 + 53_King/csharp/Resources/EndMoneyLeftOver.txt | 7 ++ 53_King/csharp/Resources/EndOneThirdDead.txt | 7 ++ 53_King/csharp/Resources/FuneralExpenses.txt | 1 + 53_King/csharp/Resources/Goodbye.txt | 1 - .../csharp/Resources/InsufficientReserves.txt | 0 53_King/csharp/Resources/PollutionEffect.txt | 5 + 53_King/csharp/Resources/Resource.cs | 24 +++++ 53_King/csharp/Year.cs | 93 +++++++++++++++++++ 53_King/king.bas | 1 - 19 files changed, 226 insertions(+), 41 deletions(-) create mode 100644 53_King/csharp/Resources/DeathsPollution.txt create mode 100644 53_King/csharp/Resources/DeathsStarvation.txt create mode 100644 53_King/csharp/Resources/EndAlso.txt create mode 100644 53_King/csharp/Resources/EndCongratulations.txt create mode 100644 53_King/csharp/Resources/EndConsequences.txt create mode 100644 53_King/csharp/Resources/EndForeignWorkers.txt create mode 100644 53_King/csharp/Resources/EndManyDead.txt create mode 100644 53_King/csharp/Resources/EndMoneyLeftOver.txt create mode 100644 53_King/csharp/Resources/EndOneThirdDead.txt create mode 100644 53_King/csharp/Resources/FuneralExpenses.txt create mode 100644 53_King/csharp/Resources/InsufficientReserves.txt create mode 100644 53_King/csharp/Resources/PollutionEffect.txt create mode 100644 53_King/csharp/Year.cs diff --git a/53_King/csharp/Country.cs b/53_King/csharp/Country.cs index 5b47c50a..b1b473e7 100644 --- a/53_King/csharp/Country.cs +++ b/53_King/csharp/Country.cs @@ -2,14 +2,15 @@ namespace King; internal class Country { + private const int InitialLand = 1000; + private readonly IReadWrite _io; private readonly IRandom _random; private float _rallods; private float _countrymen; private float _foreigners; - private float _land; - private float _plantingCost; - private float _landValue; + private float _arableLand; + private float _industryLand; public Country(IReadWrite io, IRandom random) : this( @@ -18,7 +19,7 @@ internal class Country (int)(60000 + random.NextFloat(1000) - random.NextFloat(1000)), (int)(500 + random.NextFloat(10) - random.NextFloat(10)), 0, - 2000) + InitialLand) { } @@ -29,35 +30,38 @@ internal class Country _rallods = rallods; _countrymen = countrymen; _foreigners = foreigners; - _land = land; - - _plantingCost = random.Next(10, 15); - _landValue = random.Next(95, 105); + _arableLand = land; } - public string Status => Resource.Status(_rallods, _countrymen, _foreigners, _land, _landValue, _plantingCost); - private float FarmLand => _land - 1000; + public string GetStatus(int landValue, int plantingCost) + => Resource.Status(_rallods, _countrymen, _foreigners, _arableLand, landValue, plantingCost); + + public float Countrymen => _countrymen; + private float FarmLand => _arableLand; + public bool HasRallods => _rallods > 0; + public float Rallods => _rallods; + public float IndustryLand => InitialLand - _arableLand; - public bool SellLand() + public bool SellLand(int landValue, out float landSold) { if (_io.TryReadValue( SellLandPrompt, - out var landSold, + out landSold, new ValidityTest(v => v <= FarmLand, () => SellLandError(FarmLand)))) { - _land = (int)(_land - landSold); - _rallods = (int)(_rallods + landSold * _landValue); + _arableLand = (int)(_arableLand - landSold); + _rallods = (int)(_rallods + landSold * landValue); return true; } return false; } - public bool DistributeRallods() + public bool DistributeRallods(out float rallodsGiven) { if (_io.TryReadValue( GiveRallodsPrompt, - out var rallodsGiven, + out rallodsGiven, new ValidityTest(v => v <= _rallods, () => GiveRallodsError(_rallods)))) { _rallods = (int)(_rallods - rallodsGiven); @@ -67,35 +71,48 @@ internal class Country return false; } - public bool PlantLand() + public bool PlantLand(int plantingCost, out float landPlanted) { - if (_rallods > 0 && - _io.TryReadValue( + if (_io.TryReadValue( PlantLandPrompt, - out var landPlanted, + out landPlanted, new ValidityTest(v => v <= _countrymen * 2, PlantLandError1), new ValidityTest(v => v <= FarmLand, PlantLandError2(FarmLand)), - new ValidityTest(v => v * _plantingCost <= _rallods, PlantLandError3(_rallods)))) + new ValidityTest(v => v * plantingCost <= _rallods, PlantLandError3(_rallods)))) { - _rallods -= (int)(landPlanted * _plantingCost); + _rallods -= (int)(landPlanted * plantingCost); return true; } return false; } - public bool ControlPollution() + public bool ControlPollution(out float rallodsSpent) { - if (_rallods > 0 && - _io.TryReadValue( + if (_io.TryReadValue( PollutionPrompt, - out var rallodsGiven, + out rallodsSpent, new ValidityTest(v => v <= _rallods, () => PollutionError(_rallods)))) { - _rallods = (int)(_rallods - rallodsGiven); + _rallods = (int)(_rallods - rallodsSpent); return true; } return false; } + + public bool TrySpend(float amount, float landValue) + { + if (_rallods >= amount) + { + _rallods -= amount; + return true; + } + + _arableLand = (int)(_arableLand - (int)(amount - _rallods) / landValue); + _rallods = 0; + return false; + } + + public void RemoveTheDead(int deaths) => _countrymen = (int)(_countrymen - deaths); } diff --git a/53_King/csharp/IOExtensions.cs b/53_King/csharp/IOExtensions.cs index e59bf4c0..dbb3079a 100644 --- a/53_King/csharp/IOExtensions.cs +++ b/53_King/csharp/IOExtensions.cs @@ -13,7 +13,7 @@ internal static class IOExtensions io.TryReadValue(SavedWorkersPrompt, out var workers) && io.TryReadValue(SavedLandPrompt, v => v is > 1000 and <= 2000, SavedLandError, out var land)) { - reign = new Reign(io, new Country(io, random, rallods, countrymen, workers, land), years + 1); + reign = new Reign(io, random, new Country(io, random, rallods, countrymen, workers, land), years + 1); return true; } diff --git a/53_King/csharp/Reign.cs b/53_King/csharp/Reign.cs index 2bdc9b89..727f71d3 100644 --- a/53_King/csharp/Reign.cs +++ b/53_King/csharp/Reign.cs @@ -5,37 +5,40 @@ internal class Reign public const int MaxTerm = 8; private readonly IReadWrite _io; + private readonly IRandom _random; private readonly Country _country; - private float _year; + private float _yearNumber; public Reign(IReadWrite io, IRandom random) - : this(io, new Country(io, random), 1) + : this(io, random, new Country(io, random), 1) { } - public Reign(IReadWrite io, Country country, float year) + public Reign(IReadWrite io, IRandom random, Country country, float year) { _io = io; + _random = random; _country = country; - _year = year; + _yearNumber = year; } public bool PlayYear() { - _io.Write(_country.Status); + var year = new Year(_country, _random); - var playerSoldLand = _country.SellLand(); - var playerDistributedRallods = _country.DistributeRallods(); - var playerPlantedLand = _country.PlantLand(); - var playerControlledPollution = _country.ControlPollution(); + _io.Write(year.Status); - if (playerSoldLand || playerDistributedRallods || playerPlantedLand || playerControlledPollution) + if (year.GetPlayerActions()) { - _year++; + _io.WriteLine(); + _io.WriteLine(); + year.EvaluateResults(_io, _random); + _yearNumber++; return true; } else { + _io.WriteLine(); _io.Write(Goodbye); return false; } diff --git a/53_King/csharp/Resources/DeathsPollution.txt b/53_King/csharp/Resources/DeathsPollution.txt new file mode 100644 index 00000000..bf28d9a7 --- /dev/null +++ b/53_King/csharp/Resources/DeathsPollution.txt @@ -0,0 +1 @@ + {0} countrymen died of carbon-monoxide and dust inhalation \ No newline at end of file diff --git a/53_King/csharp/Resources/DeathsStarvation.txt b/53_King/csharp/Resources/DeathsStarvation.txt new file mode 100644 index 00000000..af275cf4 --- /dev/null +++ b/53_King/csharp/Resources/DeathsStarvation.txt @@ -0,0 +1 @@ + {0} countrymen died of starvation \ No newline at end of file diff --git a/53_King/csharp/Resources/EndAlso.txt b/53_King/csharp/Resources/EndAlso.txt new file mode 100644 index 00000000..084b9a82 --- /dev/null +++ b/53_King/csharp/Resources/EndAlso.txt @@ -0,0 +1,3 @@ +also had your left eye gouged out! +;have also gained a very bad reputation. +;have also been declared national fink. diff --git a/53_King/csharp/Resources/EndCongratulations.txt b/53_King/csharp/Resources/EndCongratulations.txt new file mode 100644 index 00000000..ef1ff203 --- /dev/null +++ b/53_King/csharp/Resources/EndCongratulations.txt @@ -0,0 +1,10 @@ + + +Congratulations!!!!!!!!!!!!!!!!!! +You have successfully completed your {0} year term +of office. You were, of course, extremely lucky, but +nevertheless, it's quite an achievement. Goodbye and good +luck - you'll probably need it if you're the type that +plays this game. + + diff --git a/53_King/csharp/Resources/EndConsequences.txt b/53_King/csharp/Resources/EndConsequences.txt new file mode 100644 index 00000000..61ebfd25 --- /dev/null +++ b/53_King/csharp/Resources/EndConsequences.txt @@ -0,0 +1,3 @@ +You have been thrown out of office and are now +residing in prison.; +You have been assassinated. diff --git a/53_King/csharp/Resources/EndForeignWorkers.txt b/53_King/csharp/Resources/EndForeignWorkers.txt new file mode 100644 index 00000000..76c04c3d --- /dev/null +++ b/53_King/csharp/Resources/EndForeignWorkers.txt @@ -0,0 +1,7 @@ + + +The number of foreign workers has exceeded the number +of countrymen. As a minority, they have revolted and +taken over the country. +{0} + diff --git a/53_King/csharp/Resources/EndManyDead.txt b/53_King/csharp/Resources/EndManyDead.txt new file mode 100644 index 00000000..70cd95f0 --- /dev/null +++ b/53_King/csharp/Resources/EndManyDead.txt @@ -0,0 +1,5 @@ +{0} countrymen died in one year!!!!! +due to this extreme mismanagement, you have not only +been impeached and thrown out of office, but you +{1} + diff --git a/53_King/csharp/Resources/EndMoneyLeftOver.txt b/53_King/csharp/Resources/EndMoneyLeftOver.txt new file mode 100644 index 00000000..e194a9fd --- /dev/null +++ b/53_King/csharp/Resources/EndMoneyLeftOver.txt @@ -0,0 +1,7 @@ + +Money was left over in the treasury which you did +not spend. As a result, some of your countrymen died +of starvation. The public is enraged and you have +been forced to resign. + + diff --git a/53_King/csharp/Resources/EndOneThirdDead.txt b/53_King/csharp/Resources/EndOneThirdDead.txt new file mode 100644 index 00000000..e1761dfe --- /dev/null +++ b/53_King/csharp/Resources/EndOneThirdDead.txt @@ -0,0 +1,7 @@ + + +Over one third of the population has died since you +were elected to office. The people (remaining) +hate your guts. +{0} + diff --git a/53_King/csharp/Resources/FuneralExpenses.txt b/53_King/csharp/Resources/FuneralExpenses.txt new file mode 100644 index 00000000..3aff58eb --- /dev/null +++ b/53_King/csharp/Resources/FuneralExpenses.txt @@ -0,0 +1 @@ + You were forced to spend {0} rallods on funeral expenses \ No newline at end of file diff --git a/53_King/csharp/Resources/Goodbye.txt b/53_King/csharp/Resources/Goodbye.txt index 325890a5..67543c04 100644 --- a/53_King/csharp/Resources/Goodbye.txt +++ b/53_King/csharp/Resources/Goodbye.txt @@ -1,4 +1,3 @@ - Goodbye. (If you wish to continue this game at a later date, answer 'again' when asked if you want instructions at the start diff --git a/53_King/csharp/Resources/InsufficientReserves.txt b/53_King/csharp/Resources/InsufficientReserves.txt new file mode 100644 index 00000000..e69de29b diff --git a/53_King/csharp/Resources/PollutionEffect.txt b/53_King/csharp/Resources/PollutionEffect.txt new file mode 100644 index 00000000..b3535c3d --- /dev/null +++ b/53_King/csharp/Resources/PollutionEffect.txt @@ -0,0 +1,5 @@ +fish population has dwindled due to water pollution. +;air pollution is killing game bird population. +;mineral baths are being ruined by water pollution. +;unpleasant smog is discouraging sun bathers. +;hotels are looking shabby due to smog grit. diff --git a/53_King/csharp/Resources/Resource.cs b/53_King/csharp/Resources/Resource.cs index cf555583..496bc250 100644 --- a/53_King/csharp/Resources/Resource.cs +++ b/53_King/csharp/Resources/Resource.cs @@ -51,6 +51,28 @@ internal static class Resource public static string PollutionPrompt => GetString(); public static string PollutionError(float rallods) => string.Format(GetString(), rallods); + public static string DeathsStarvation(float deaths) => string.Format(GetString(), (int)deaths); + public static string DeathsPollution(int deaths) => string.Format(GetString(), deaths); + public static string FuneralExpenses(int expenses) => string.Format(GetString(), expenses); + public static string InsufficientReserves => GetString(); + + private static string PollutionEffect(IRandom random) => GetStrings()[random.Next(5)]; + + private static string EndAlso(IRandom random) + => random.Next(10) switch + { + <= 3 => GetStrings()[0], + <= 6 => GetStrings()[1], + _ => GetStrings()[2] + }; + + public static string EndCongratulations(int termLength) => string.Format(GetString(), termLength); + private static string EndConsequences(IRandom random) => GetStrings()[random.Next(2)]; + public static string EndForeignWorkers(IRandom random) => string.Format(GetString(), EndConsequences(random)); + public static string EndManyDead(int deaths, IRandom random) => string.Format(GetString(), deaths, EndAlso(random)); + public static string EndMoneyLeftOver(int termLength) => string.Format(GetString(), termLength); + public static string EndOneThirdDead(IRandom random) => string.Format(GetString(), EndConsequences(random)); + public static string SavedYearsPrompt => GetString(); public static string SavedYearsError(int years) => string.Format(GetString(), years); public static string SavedTreasuryPrompt => GetString(); @@ -61,6 +83,8 @@ internal static class Resource public static string Goodbye => GetString(); + private static string[] GetStrings([CallerMemberName] string? name = null) => GetString(name).Split(';'); + private static string GetString([CallerMemberName] string? name = null) { using var stream = GetStream(name); diff --git a/53_King/csharp/Year.cs b/53_King/csharp/Year.cs new file mode 100644 index 00000000..18f208e4 --- /dev/null +++ b/53_King/csharp/Year.cs @@ -0,0 +1,93 @@ +using System.Text; + +namespace King; + +internal class Year +{ + private readonly Country _country; + private readonly IRandom _random; + private readonly int _plantingCost; + private readonly int _landValue; + + private float _landSold; + private float _rallodsDistributed; + private float _landPlanted; + private float _pollutionControlCost; + + public Year(Country country, IRandom random) + { + _country = country; + _random = random; + + _plantingCost = random.Next(10, 15); + _landValue = random.Next(95, 105); + } + + public string Status => _country.GetStatus(_landValue, _plantingCost); + + public bool GetPlayerActions() + { + var playerSoldLand = _country.SellLand(_landValue, out _landSold); + var playerDistributedRallods = _country.DistributeRallods(out _rallodsDistributed); + var playerPlantedLand = _country.HasRallods && _country.PlantLand(_plantingCost, out _landPlanted); + var playerControlledPollution = _country.HasRallods && _country.ControlPollution(out _pollutionControlCost); + + return playerSoldLand || playerDistributedRallods || playerPlantedLand || playerControlledPollution; + } + + public Result EvaluateResults(IReadWrite io) + { + var unspentRallods = _country.Rallods; + var statusUpdate = new StringBuilder(); + + var result = EvaluateDeaths(statusUpdate, out var deaths); + + io.Write(statusUpdate); + + return Result.Continue; + } + + public Result? EvaluateDeaths(StringBuilder statusUpdate, out int deaths) + { + deaths = default; + + var supportedCountrymen = _rallodsDistributed / 100; + var starvationDeaths = _country.Countrymen - supportedCountrymen; + if (starvationDeaths > 0) + { + if (supportedCountrymen < 50) { return Result.GameOver(EndOneThirdDead(_random)); } + statusUpdate.AppendLine(DeathsStarvation(starvationDeaths)); + } + + var pollutionControl = _pollutionControlCost >= 25 ? _pollutionControlCost / 25 : 1; + var pollutionDeaths = (int)(_random.Next((int)_country.IndustryLand) / pollutionControl); + if (pollutionDeaths > 0) + { + statusUpdate.AppendLine(DeathsPollution(pollutionDeaths)); + } + + deaths = (int)(starvationDeaths + pollutionDeaths); + if (deaths > 0) + { + var funeralCosts = deaths * 9; + statusUpdate.AppendLine(FuneralExpenses(funeralCosts)); + + if (!_country.TrySpend(funeralCosts, _landValue)) + { + statusUpdate.AppendLine(InsufficientReserves); + } + + _country.RemoveTheDead(deaths); + } + + return null; + } + + + internal record struct Result (bool IsGameOver, string Message) + { + internal static Result GameOver(string message) => new(true, message); + internal static Result Continue => new(false, ""); + } +} + diff --git a/53_King/king.bas b/53_King/king.bas index 5e9ae163..7352fa58 100644 --- a/53_King/king.bas +++ b/53_King/king.bas @@ -99,7 +99,6 @@ 1000 GOTO 600 1002 PRINT 1003 PRINT -1005 PRINT A 1010 A=INT(A-K) 1020 A4=A 1100 IF INT(I/100-B)>=0 THEN 1120 From 051f3eb5d5d2595cb719fe7eea0c072166ac4fae Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Thu, 19 Jan 2023 07:36:00 +1100 Subject: [PATCH 6/7] Add evaluation of migration and agriculture --- 53_King/README.md | 16 ++++- 53_King/csharp/Country.cs | 7 ++ 53_King/csharp/Reign.cs | 4 +- 53_King/csharp/Resources/Emigration.txt | 1 + 53_King/csharp/Resources/Harvest.txt | 2 + 53_King/csharp/Resources/HarvestReason.txt | 1 + 53_King/csharp/Resources/Immigration.txt | 1 + 53_King/csharp/Resources/LandPlanted.txt | 1 + 53_King/csharp/Resources/Resource.cs | 12 ++++ 53_King/csharp/Resources/WorkerMigration.txt | 1 + 53_King/csharp/Year.cs | 73 ++++++++++++++------ 11 files changed, 95 insertions(+), 24 deletions(-) create mode 100644 53_King/csharp/Resources/Emigration.txt create mode 100644 53_King/csharp/Resources/Harvest.txt create mode 100644 53_King/csharp/Resources/HarvestReason.txt create mode 100644 53_King/csharp/Resources/Immigration.txt create mode 100644 53_King/csharp/Resources/LandPlanted.txt create mode 100644 53_King/csharp/Resources/WorkerMigration.txt diff --git a/53_King/README.md b/53_King/README.md index a363a2be..14a66fe9 100644 --- a/53_King/README.md +++ b/53_King/README.md @@ -1,10 +1,10 @@ ## King -This is one of the most comprehensive, difficult, and interesting games. (If you’ve never played one of these games, start with HAMMURABI.) +This is one of the most comprehensive, difficult, and interesting games. (If you've never played one of these games, start with HAMMURABI.) In this game, you are Premier of Setats Detinu, a small communist island 30 by 70 miles long. Your job is to decide upon the budget of your country and distribute money to your country from the communal treasury. -The money system is Rollods; each person needs 100 Rallods per year to survive. Your country’s income comes from farm produce and tourists visiting your magnificent forests, hunting, fishing, etc. Part of your land is farm land but it also has an excellent mineral content and may be sold to foreign industry for strip mining. Industry import and support their own workers. Crops cost between 10 and 15 Rallods per square mile to plant, cultivate, and harvest. Your goal is to complete an eight-year term of office without major mishap. A word of warning: it isn’t easy! +The money system is Rollods; each person needs 100 Rallods per year to survive. Your country's income comes from farm produce and tourists visiting your magnificent forests, hunting, fishing, etc. Part of your land is farm land but it also has an excellent mineral content and may be sold to foreign industry for strip mining. Industry import and support their own workers. Crops cost between 10 and 15 Rallods per square mile to plant, cultivate, and harvest. Your goal is to complete an eight-year term of office without major mishap. A word of warning: it isn't easy! The author of this program is James A. Storer who wrote it while a student at Lexington High School. @@ -66,3 +66,15 @@ On basic line 1997 it is: but it should be: 1997 PRINT " AND 1,000 SQ. MILES OF FOREST LAND." + +### Bug 4 + +On basic line 1310 we see this: + + 1310 IF C=0 THEN 1324 + 1320 PRINT "OF ";INT(J);"SQ. MILES PLANTED,"; + 1324 ... + +but it should probably be: + + 1310 IF J=0 THEN 1324 diff --git a/53_King/csharp/Country.cs b/53_King/csharp/Country.cs index b1b473e7..d1ba9235 100644 --- a/53_King/csharp/Country.cs +++ b/53_King/csharp/Country.cs @@ -37,6 +37,7 @@ internal class Country => Resource.Status(_rallods, _countrymen, _foreigners, _arableLand, landValue, plantingCost); public float Countrymen => _countrymen; + public bool HasWorkers => _foreigners > 0; private float FarmLand => _arableLand; public bool HasRallods => _rallods > 0; public float Rallods => _rallods; @@ -115,4 +116,10 @@ internal class Country } public void RemoveTheDead(int deaths) => _countrymen = (int)(_countrymen - deaths); + + public void Migration(int migration) => _countrymen = (int)(_countrymen + migration); + + public void AddWorkers(int newWorkers) => _foreigners = (int)(_foreigners + newWorkers); + + public void SellCrops(int income) => _rallods = (int)(_rallods + income); } diff --git a/53_King/csharp/Reign.cs b/53_King/csharp/Reign.cs index 727f71d3..1955c81b 100644 --- a/53_King/csharp/Reign.cs +++ b/53_King/csharp/Reign.cs @@ -24,7 +24,7 @@ internal class Reign public bool PlayYear() { - var year = new Year(_country, _random); + var year = new Year(_country, _random, _io); _io.Write(year.Status); @@ -32,7 +32,7 @@ internal class Reign { _io.WriteLine(); _io.WriteLine(); - year.EvaluateResults(_io, _random); + year.EvaluateResults(); _yearNumber++; return true; } diff --git a/53_King/csharp/Resources/Emigration.txt b/53_King/csharp/Resources/Emigration.txt new file mode 100644 index 00000000..01f67094 --- /dev/null +++ b/53_King/csharp/Resources/Emigration.txt @@ -0,0 +1 @@ + {0} countrymen left the island. \ No newline at end of file diff --git a/53_King/csharp/Resources/Harvest.txt b/53_King/csharp/Resources/Harvest.txt new file mode 100644 index 00000000..7cedf658 --- /dev/null +++ b/53_King/csharp/Resources/Harvest.txt @@ -0,0 +1,2 @@ + you harvested {0} sq. miles of crops. +{1}making {2} rallods. \ No newline at end of file diff --git a/53_King/csharp/Resources/HarvestReason.txt b/53_King/csharp/Resources/HarvestReason.txt new file mode 100644 index 00000000..82faccb5 --- /dev/null +++ b/53_King/csharp/Resources/HarvestReason.txt @@ -0,0 +1 @@ + (Due to increased air and water pollution from foreign industry.) diff --git a/53_King/csharp/Resources/Immigration.txt b/53_King/csharp/Resources/Immigration.txt new file mode 100644 index 00000000..30d8b6b3 --- /dev/null +++ b/53_King/csharp/Resources/Immigration.txt @@ -0,0 +1 @@ + {0} countrymen came to the island. \ No newline at end of file diff --git a/53_King/csharp/Resources/LandPlanted.txt b/53_King/csharp/Resources/LandPlanted.txt new file mode 100644 index 00000000..e52529aa --- /dev/null +++ b/53_King/csharp/Resources/LandPlanted.txt @@ -0,0 +1 @@ +Of {0} sq. miles planted, \ No newline at end of file diff --git a/53_King/csharp/Resources/Resource.cs b/53_King/csharp/Resources/Resource.cs index 496bc250..9fd56b8d 100644 --- a/53_King/csharp/Resources/Resource.cs +++ b/53_King/csharp/Resources/Resource.cs @@ -56,6 +56,18 @@ internal static class Resource public static string FuneralExpenses(int expenses) => string.Format(GetString(), expenses); public static string InsufficientReserves => GetString(); + public static string WorkerMigration(int newWorkers) => string.Format(GetString(), newWorkers); + public static string Migration(int migration) + => string.Format(migration < 0 ? Emigration : Immigration, Math.Abs(migration)); + public static string Emigration => GetString(); + public static string Immigration => GetString(); + + public static string LandPlanted(float landPlanted) + => landPlanted > 0 ? string.Format(GetString(), (int)landPlanted) : ""; + public static string Harvest(int yield, int income, bool hasIndustry) + => string.Format(GetString(), yield, HarvestReason(hasIndustry), income); + private static string HarvestReason(bool hasIndustry) => hasIndustry ? GetString() : ""; + private static string PollutionEffect(IRandom random) => GetStrings()[random.Next(5)]; private static string EndAlso(IRandom random) diff --git a/53_King/csharp/Resources/WorkerMigration.txt b/53_King/csharp/Resources/WorkerMigration.txt new file mode 100644 index 00000000..d2f3b378 --- /dev/null +++ b/53_King/csharp/Resources/WorkerMigration.txt @@ -0,0 +1 @@ + {0} workers came to the country and \ No newline at end of file diff --git a/53_King/csharp/Year.cs b/53_King/csharp/Year.cs index 18f208e4..526db454 100644 --- a/53_King/csharp/Year.cs +++ b/53_King/csharp/Year.cs @@ -6,6 +6,7 @@ internal class Year { private readonly Country _country; private readonly IRandom _random; + private readonly IReadWrite _io; private readonly int _plantingCost; private readonly int _landValue; @@ -14,7 +15,12 @@ internal class Year private float _landPlanted; private float _pollutionControlCost; - public Year(Country country, IRandom random) + private float _citizenSupport; + private int _deaths; + private int _pollutionDeaths; + + + public Year(Country country, IRandom random, IReadWrite io) { _country = country; _random = random; @@ -35,54 +41,81 @@ internal class Year return playerSoldLand || playerDistributedRallods || playerPlantedLand || playerControlledPollution; } - public Result EvaluateResults(IReadWrite io) + public Result EvaluateResults() { var unspentRallods = _country.Rallods; - var statusUpdate = new StringBuilder(); - var result = EvaluateDeaths(statusUpdate, out var deaths); - - io.Write(statusUpdate); + var result = EvaluateDeaths(); return Result.Continue; } - public Result? EvaluateDeaths(StringBuilder statusUpdate, out int deaths) + public Result? EvaluateDeaths() { - deaths = default; - var supportedCountrymen = _rallodsDistributed / 100; - var starvationDeaths = _country.Countrymen - supportedCountrymen; + _citizenSupport = supportedCountrymen - _country.Countrymen; + var starvationDeaths = -_citizenSupport; if (starvationDeaths > 0) { if (supportedCountrymen < 50) { return Result.GameOver(EndOneThirdDead(_random)); } - statusUpdate.AppendLine(DeathsStarvation(starvationDeaths)); + _io.WriteLine(DeathsStarvation(starvationDeaths)); } var pollutionControl = _pollutionControlCost >= 25 ? _pollutionControlCost / 25 : 1; - var pollutionDeaths = (int)(_random.Next((int)_country.IndustryLand) / pollutionControl); - if (pollutionDeaths > 0) + _pollutionDeaths = (int)(_random.Next((int)_country.IndustryLand) / pollutionControl); + if (_pollutionDeaths > 0) { - statusUpdate.AppendLine(DeathsPollution(pollutionDeaths)); + _io.WriteLine(DeathsPollution(_pollutionDeaths)); } - deaths = (int)(starvationDeaths + pollutionDeaths); - if (deaths > 0) + _deaths = (int)(starvationDeaths + _pollutionDeaths); + if (_deaths > 0) { - var funeralCosts = deaths * 9; - statusUpdate.AppendLine(FuneralExpenses(funeralCosts)); + var funeralCosts = _deaths * 9; + _io.WriteLine(FuneralExpenses(funeralCosts)); if (!_country.TrySpend(funeralCosts, _landValue)) { - statusUpdate.AppendLine(InsufficientReserves); + _io.WriteLine(InsufficientReserves); } - _country.RemoveTheDead(deaths); + _country.RemoveTheDead(_deaths); } return null; } + private Result? EvaluateMigration() + { + if (_landSold > 0) + { + var newWorkers = (int)(_landSold + _random.NextFloat(10) - _random.NextFloat(20)); + if (!_country.HasWorkers) { newWorkers += 20; } + _io.Write(WorkerMigration(newWorkers)); + _country.AddWorkers(newWorkers); + } + + var migration = + (int)(_citizenSupport / 10 + _pollutionControlCost / 25 - _country.IndustryLand / 50 - _pollutionDeaths / 2); + _io.WriteLine(Migration(migration)); + _country.Migration(migration); + + return null; + } + + private Result? EvaluateAgriculture() + { + var ruinedCrops = (int)Math.Min(_country.IndustryLand * (_random.NextFloat() + 1.5f) / 2, _landPlanted); + var yield = (int)(_landPlanted - ruinedCrops); + var income = (int)(yield * _landValue / 2f); + + _io.Write(LandPlanted(_landPlanted)); + _io.Write(Harvest(yield, income, _country.IndustryLand > 0)); + + _country.SellCrops(income); + + return null; + } internal record struct Result (bool IsGameOver, string Message) { From 62db3a9c9a7994d468a2238fc618be7532b71afb Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sat, 21 Jan 2023 22:24:20 +1100 Subject: [PATCH 7/7] Finish game --- 53_King/csharp/Country.cs | 8 +++ 53_King/csharp/Game.cs | 6 +- 53_King/csharp/Reign.cs | 21 +++--- 53_King/csharp/Resources/Harvest.txt | 2 +- 53_King/csharp/Resources/Resource.cs | 7 +- 53_King/csharp/Resources/TourismDecrease.txt | 1 + 53_King/csharp/Resources/TourismEarnings.txt | 1 + ...{PollutionEffect.txt => TourismReason.txt} | 0 53_King/csharp/Result.cs | 7 ++ 53_King/csharp/Year.cs | 64 +++++++++++++------ 10 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 53_King/csharp/Resources/TourismDecrease.txt create mode 100644 53_King/csharp/Resources/TourismEarnings.txt rename 53_King/csharp/Resources/{PollutionEffect.txt => TourismReason.txt} (100%) create mode 100644 53_King/csharp/Result.cs diff --git a/53_King/csharp/Country.cs b/53_King/csharp/Country.cs index d1ba9235..1a37bcd8 100644 --- a/53_King/csharp/Country.cs +++ b/53_King/csharp/Country.cs @@ -37,11 +37,13 @@ internal class Country => Resource.Status(_rallods, _countrymen, _foreigners, _arableLand, landValue, plantingCost); public float Countrymen => _countrymen; + public float Workers => _foreigners; public bool HasWorkers => _foreigners > 0; private float FarmLand => _arableLand; public bool HasRallods => _rallods > 0; public float Rallods => _rallods; public float IndustryLand => InitialLand - _arableLand; + public int PreviousTourismIncome { get; private set; } public bool SellLand(int landValue, out float landSold) { @@ -122,4 +124,10 @@ internal class Country public void AddWorkers(int newWorkers) => _foreigners = (int)(_foreigners + newWorkers); public void SellCrops(int income) => _rallods = (int)(_rallods + income); + + public void EntertainTourists(int income) + { + PreviousTourismIncome = income; + _rallods = (int)(_rallods + income); + } } diff --git a/53_King/csharp/Game.cs b/53_King/csharp/Game.cs index 92d8063f..6a91010c 100644 --- a/53_King/csharp/Game.cs +++ b/53_King/csharp/Game.cs @@ -15,7 +15,7 @@ internal class Game public void Play() { - _io.Write(Resource.Title); + _io.Write(Title); var reign = SetUpReign(); if (reign != null) @@ -29,7 +29,7 @@ internal class Game private Reign? SetUpReign() { - var response = _io.ReadString(Resource.InstructionsPrompt).ToUpper(); + var response = _io.ReadString(InstructionsPrompt).ToUpper(); if (response.Equals("Again", StringComparison.InvariantCultureIgnoreCase)) { @@ -38,7 +38,7 @@ internal class Game if (!response.StartsWith("N", StringComparison.InvariantCultureIgnoreCase)) { - _io.Write(Resource.InstructionsText(TermOfOffice)); + _io.Write(InstructionsText(TermOfOffice)); } _io.WriteLine(); diff --git a/53_King/csharp/Reign.cs b/53_King/csharp/Reign.cs index 1955c81b..7a96a30f 100644 --- a/53_King/csharp/Reign.cs +++ b/53_King/csharp/Reign.cs @@ -28,19 +28,18 @@ internal class Reign _io.Write(year.Status); - if (year.GetPlayerActions()) + var result = year.GetPlayerActions() ?? year.EvaluateResults() ?? IsAtEndOfTerm(); + if (result.IsGameOver) { - _io.WriteLine(); - _io.WriteLine(); - year.EvaluateResults(); - _yearNumber++; - return true; - } - else - { - _io.WriteLine(); - _io.Write(Goodbye); + _io.WriteLine(result.Message); return false; } + + return true; } + + private Result IsAtEndOfTerm() + => _yearNumber == MaxTerm + ? Result.GameOver(EndCongratulations(MaxTerm)) + : Result.Continue; } diff --git a/53_King/csharp/Resources/Harvest.txt b/53_King/csharp/Resources/Harvest.txt index 7cedf658..287e0c42 100644 --- a/53_King/csharp/Resources/Harvest.txt +++ b/53_King/csharp/Resources/Harvest.txt @@ -1,2 +1,2 @@ you harvested {0} sq. miles of crops. -{1}making {2} rallods. \ No newline at end of file +{1}making {2} rallods. diff --git a/53_King/csharp/Resources/Resource.cs b/53_King/csharp/Resources/Resource.cs index 9fd56b8d..5ea09e1c 100644 --- a/53_King/csharp/Resources/Resource.cs +++ b/53_King/csharp/Resources/Resource.cs @@ -68,7 +68,9 @@ internal static class Resource => string.Format(GetString(), yield, HarvestReason(hasIndustry), income); private static string HarvestReason(bool hasIndustry) => hasIndustry ? GetString() : ""; - private static string PollutionEffect(IRandom random) => GetStrings()[random.Next(5)]; + public static string TourismEarnings(int income) => string.Format(GetString(), income); + public static string TourismDecrease(IRandom random) => string.Format(GetString(), TourismReason(random)); + private static string TourismReason(IRandom random) => GetStrings()[random.Next(5)]; private static string EndAlso(IRandom random) => random.Next(10) switch @@ -82,7 +84,7 @@ internal static class Resource private static string EndConsequences(IRandom random) => GetStrings()[random.Next(2)]; public static string EndForeignWorkers(IRandom random) => string.Format(GetString(), EndConsequences(random)); public static string EndManyDead(int deaths, IRandom random) => string.Format(GetString(), deaths, EndAlso(random)); - public static string EndMoneyLeftOver(int termLength) => string.Format(GetString(), termLength); + public static string EndMoneyLeftOver() => GetString(); public static string EndOneThirdDead(IRandom random) => string.Format(GetString(), EndConsequences(random)); public static string SavedYearsPrompt => GetString(); @@ -104,7 +106,6 @@ internal static class Resource 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}'."); diff --git a/53_King/csharp/Resources/TourismDecrease.txt b/53_King/csharp/Resources/TourismDecrease.txt new file mode 100644 index 00000000..dcb45fc7 --- /dev/null +++ b/53_King/csharp/Resources/TourismDecrease.txt @@ -0,0 +1 @@ + Decrease because {0} \ No newline at end of file diff --git a/53_King/csharp/Resources/TourismEarnings.txt b/53_King/csharp/Resources/TourismEarnings.txt new file mode 100644 index 00000000..db9251dd --- /dev/null +++ b/53_King/csharp/Resources/TourismEarnings.txt @@ -0,0 +1 @@ + You made {0} rallods from tourist trade. \ No newline at end of file diff --git a/53_King/csharp/Resources/PollutionEffect.txt b/53_King/csharp/Resources/TourismReason.txt similarity index 100% rename from 53_King/csharp/Resources/PollutionEffect.txt rename to 53_King/csharp/Resources/TourismReason.txt diff --git a/53_King/csharp/Result.cs b/53_King/csharp/Result.cs new file mode 100644 index 00000000..185f4617 --- /dev/null +++ b/53_King/csharp/Result.cs @@ -0,0 +1,7 @@ +namespace King; + +internal record struct Result (bool IsGameOver, string Message) +{ + internal static Result GameOver(string message) => new(true, message); + internal static Result Continue => new(false, ""); +} diff --git a/53_King/csharp/Year.cs b/53_King/csharp/Year.cs index 526db454..8e6bb0b4 100644 --- a/53_King/csharp/Year.cs +++ b/53_King/csharp/Year.cs @@ -17,13 +17,15 @@ internal class Year private float _citizenSupport; private int _deaths; + private float _starvationDeaths; private int _pollutionDeaths; - + private int _migration; public Year(Country country, IRandom random, IReadWrite io) { _country = country; _random = random; + _io = io; _plantingCost = random.Next(10, 15); _landValue = random.Next(95, 105); @@ -31,34 +33,41 @@ internal class Year public string Status => _country.GetStatus(_landValue, _plantingCost); - public bool GetPlayerActions() + public Result? GetPlayerActions() { var playerSoldLand = _country.SellLand(_landValue, out _landSold); var playerDistributedRallods = _country.DistributeRallods(out _rallodsDistributed); var playerPlantedLand = _country.HasRallods && _country.PlantLand(_plantingCost, out _landPlanted); var playerControlledPollution = _country.HasRallods && _country.ControlPollution(out _pollutionControlCost); - return playerSoldLand || playerDistributedRallods || playerPlantedLand || playerControlledPollution; + return playerSoldLand || playerDistributedRallods || playerPlantedLand || playerControlledPollution + ? null + : Result.GameOver(Goodbye); } - public Result EvaluateResults() + public Result? EvaluateResults() { - var unspentRallods = _country.Rallods; + var rallodsUnspent = _country.Rallods; - var result = EvaluateDeaths(); + _io.WriteLine(); + _io.WriteLine(); - return Result.Continue; + return EvaluateDeaths() + ?? EvaluateMigration() + ?? EvaluateAgriculture() + ?? EvaluateTourism() + ?? DetermineResult(rallodsUnspent); } public Result? EvaluateDeaths() { var supportedCountrymen = _rallodsDistributed / 100; _citizenSupport = supportedCountrymen - _country.Countrymen; - var starvationDeaths = -_citizenSupport; - if (starvationDeaths > 0) + _starvationDeaths = -_citizenSupport; + if (_starvationDeaths > 0) { if (supportedCountrymen < 50) { return Result.GameOver(EndOneThirdDead(_random)); } - _io.WriteLine(DeathsStarvation(starvationDeaths)); + _io.WriteLine(DeathsStarvation(_starvationDeaths)); } var pollutionControl = _pollutionControlCost >= 25 ? _pollutionControlCost / 25 : 1; @@ -68,7 +77,7 @@ internal class Year _io.WriteLine(DeathsPollution(_pollutionDeaths)); } - _deaths = (int)(starvationDeaths + _pollutionDeaths); + _deaths = (int)(_starvationDeaths + _pollutionDeaths); if (_deaths > 0) { var funeralCosts = _deaths * 9; @@ -95,10 +104,10 @@ internal class Year _country.AddWorkers(newWorkers); } - var migration = + _migration = (int)(_citizenSupport / 10 + _pollutionControlCost / 25 - _country.IndustryLand / 50 - _pollutionDeaths / 2); - _io.WriteLine(Migration(migration)); - _country.Migration(migration); + _io.WriteLine(Migration(_migration)); + _country.Migration(_migration); return null; } @@ -117,10 +126,29 @@ internal class Year return null; } - internal record struct Result (bool IsGameOver, string Message) + private Result? EvaluateTourism() { - internal static Result GameOver(string message) => new(true, message); - internal static Result Continue => new(false, ""); + var reputationValue = (int)((_country.Countrymen - _migration) * 22 + _random.NextFloat(500)); + var industryAdjustment = (int)(_country.IndustryLand * 15); + var tourismIncome = Math.Abs(reputationValue - industryAdjustment); + + _io.WriteLine(TourismEarnings(tourismIncome)); + if (industryAdjustment > 0 && tourismIncome < _country.PreviousTourismIncome) + { + _io.Write(TourismDecrease(_random)); + } + + _country.EntertainTourists(tourismIncome); + + return null; + } + + private Result? DetermineResult(float rallodsUnspent) + { + if (_deaths > 200) { return Result.GameOver(EndManyDead(_deaths, _random)); } + if (_country.Countrymen < 343) { return Result.GameOver(EndOneThirdDead(_random)); } + if (rallodsUnspent / 100 > 5 && _starvationDeaths >= 2) { return Result.GameOver(EndMoneyLeftOver()); } + if (_country.Workers > _country.Countrymen) { return Result.GameOver(EndForeignWorkers(_random)); } + return null; } } -