mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 07:10:42 -08:00
Add player input routines
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ internal class Game
|
||||
|
||||
if (SetUpReign() is Reign reign)
|
||||
{
|
||||
_io.Write(reign);
|
||||
reign.PlayYear();
|
||||
}
|
||||
|
||||
_io.WriteLine();
|
||||
|
||||
@@ -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<float> isValid,
|
||||
string error,
|
||||
out float value)
|
||||
=> io.TryReadValue(prompt, isValid, () => error, out value);
|
||||
|
||||
internal static bool TryReadValue(
|
||||
this IReadWrite io,
|
||||
string prompt,
|
||||
Predicate<float> isValid,
|
||||
Func<string> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
1
53_King/csharp/Resources/GiveRallodsError.txt
Normal file
1
53_King/csharp/Resources/GiveRallodsError.txt
Normal file
@@ -0,0 +1 @@
|
||||
Think again. You've only got {0} rallods in the treasury.
|
||||
1
53_King/csharp/Resources/GiveRallodsPrompt.txt
Normal file
1
53_King/csharp/Resources/GiveRallodsPrompt.txt
Normal file
@@ -0,0 +1 @@
|
||||
How many rallods will you distribute among your countrymen
|
||||
1
53_King/csharp/Resources/PlantLandError1.txt
Normal file
1
53_King/csharp/Resources/PlantLandError1.txt
Normal file
@@ -0,0 +1 @@
|
||||
Sorry, but each countryman can only plant 2 sq. miles.
|
||||
1
53_King/csharp/Resources/PlantLandError2.txt
Normal file
1
53_King/csharp/Resources/PlantLandError2.txt
Normal file
@@ -0,0 +1 @@
|
||||
Sorry, but you've only {0} sq. miles of farm land.
|
||||
1
53_King/csharp/Resources/PlantLandError3.txt
Normal file
1
53_King/csharp/Resources/PlantLandError3.txt
Normal file
@@ -0,0 +1 @@
|
||||
Think again, You've only {0} rallods left in the treasury.
|
||||
1
53_King/csharp/Resources/PlantLandPrompt.txt
Normal file
1
53_King/csharp/Resources/PlantLandPrompt.txt
Normal file
@@ -0,0 +1 @@
|
||||
How many square miles do you wish to plant
|
||||
1
53_King/csharp/Resources/PollutionError.txt
Normal file
1
53_King/csharp/Resources/PollutionError.txt
Normal file
@@ -0,0 +1 @@
|
||||
Think again. You only have {0} rallods remaining.
|
||||
1
53_King/csharp/Resources/PollutionPrompt.txt
Normal file
1
53_King/csharp/Resources/PollutionPrompt.txt
Normal file
@@ -0,0 +1 @@
|
||||
How many rallods do you wish to spend on pollution control
|
||||
@@ -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();
|
||||
@@ -18,27 +59,6 @@ internal static class Resource
|
||||
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)
|
||||
{
|
||||
using var stream = GetStream(name);
|
||||
|
||||
2
53_King/csharp/Resources/SellLandError.txt
Normal file
2
53_King/csharp/Resources/SellLandError.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
*** Think again. You only have {0} square miles of farm land.
|
||||
{1}
|
||||
4
53_King/csharp/Resources/SellLandErrorReason.txt
Normal file
4
53_King/csharp/Resources/SellLandErrorReason.txt
Normal file
@@ -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.)
|
||||
1
53_King/csharp/Resources/SellLandPrompt.txt
Normal file
1
53_King/csharp/Resources/SellLandPrompt.txt
Normal file
@@ -0,0 +1 @@
|
||||
How many square miles do you wish to sell to industry
|
||||
6
53_King/csharp/Resources/StatusSansWorkers.txt
Normal file
6
53_King/csharp/Resources/StatusSansWorkers.txt
Normal file
@@ -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.
|
||||
|
||||
6
53_King/csharp/Resources/StatusWithWorkers.txt
Normal file
6
53_King/csharp/Resources/StatusWithWorkers.txt
Normal file
@@ -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.
|
||||
|
||||
26
53_King/csharp/ValidityTest.cs
Normal file
26
53_King/csharp/ValidityTest.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace King;
|
||||
|
||||
internal class ValidityTest
|
||||
{
|
||||
private readonly Predicate<float> _isValid;
|
||||
private readonly Func<string> _getError;
|
||||
|
||||
public ValidityTest(Predicate<float> isValid, string error)
|
||||
: this(isValid, () => error)
|
||||
{
|
||||
}
|
||||
|
||||
public ValidityTest(Predicate<float> isValid, Func<string> getError)
|
||||
{
|
||||
_isValid = isValid;
|
||||
_getError = getError;
|
||||
}
|
||||
|
||||
public bool IsValid(float value, IReadWrite io)
|
||||
{
|
||||
if (_isValid(value)) { return true; }
|
||||
|
||||
io.Write(_getError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user