mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-07-04 19:56:59 -07:00
+14
-2
@@ -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
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
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 _arableLand;
|
||||
private float _industryLand;
|
||||
|
||||
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)),
|
||||
0,
|
||||
InitialLand)
|
||||
{
|
||||
}
|
||||
|
||||
public Country(IReadWrite io, IRandom random, float rallods, float countrymen, float foreigners, float land)
|
||||
{
|
||||
_io = io;
|
||||
_random = random;
|
||||
_rallods = rallods;
|
||||
_countrymen = countrymen;
|
||||
_foreigners = foreigners;
|
||||
_arableLand = land;
|
||||
}
|
||||
|
||||
public string GetStatus(int landValue, int plantingCost)
|
||||
=> 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)
|
||||
{
|
||||
if (_io.TryReadValue(
|
||||
SellLandPrompt,
|
||||
out landSold,
|
||||
new ValidityTest(v => v <= FarmLand, () => SellLandError(FarmLand))))
|
||||
{
|
||||
_arableLand = (int)(_arableLand - landSold);
|
||||
_rallods = (int)(_rallods + landSold * landValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool DistributeRallods(out float rallodsGiven)
|
||||
{
|
||||
if (_io.TryReadValue(
|
||||
GiveRallodsPrompt,
|
||||
out rallodsGiven,
|
||||
new ValidityTest(v => v <= _rallods, () => GiveRallodsError(_rallods))))
|
||||
{
|
||||
_rallods = (int)(_rallods - rallodsGiven);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool PlantLand(int plantingCost, out float landPlanted)
|
||||
{
|
||||
if (_io.TryReadValue(
|
||||
PlantLandPrompt,
|
||||
out 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(out float rallodsSpent)
|
||||
{
|
||||
if (_io.TryReadValue(
|
||||
PollutionPrompt,
|
||||
out rallodsSpent,
|
||||
new ValidityTest(v => v <= _rallods, () => PollutionError(_rallods))))
|
||||
{
|
||||
_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);
|
||||
|
||||
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);
|
||||
|
||||
public void EntertainTourists(int income)
|
||||
{
|
||||
PreviousTourismIncome = income;
|
||||
_rallods = (int)(_rallods + income);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
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(Title);
|
||||
|
||||
var reign = SetUpReign();
|
||||
if (reign != null)
|
||||
{
|
||||
while (reign.PlayYear());
|
||||
}
|
||||
|
||||
_io.WriteLine();
|
||||
_io.WriteLine();
|
||||
}
|
||||
|
||||
private Reign? SetUpReign()
|
||||
{
|
||||
var response = _io.ReadString(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(InstructionsText(TermOfOffice));
|
||||
}
|
||||
|
||||
_io.WriteLine();
|
||||
return new Reign(_io, _random);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
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, random, new Country(io, random, rallods, countrymen, workers, land), years + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
reign = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
value = io.ReadNumber(prompt);
|
||||
if (value < 0) { return false; }
|
||||
if (isValid(value)) { return true; }
|
||||
|
||||
io.Write(getError());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,4 +6,12 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources/*.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\00_Common\dotnet\Games.Common\Games.Common.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +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();
|
||||
@@ -0,0 +1,45 @@
|
||||
namespace King;
|
||||
|
||||
internal class Reign
|
||||
{
|
||||
public const int MaxTerm = 8;
|
||||
|
||||
private readonly IReadWrite _io;
|
||||
private readonly IRandom _random;
|
||||
private readonly Country _country;
|
||||
private float _yearNumber;
|
||||
|
||||
public Reign(IReadWrite io, IRandom random)
|
||||
: this(io, random, new Country(io, random), 1)
|
||||
{
|
||||
}
|
||||
|
||||
public Reign(IReadWrite io, IRandom random, Country country, float year)
|
||||
{
|
||||
_io = io;
|
||||
_random = random;
|
||||
_country = country;
|
||||
_yearNumber = year;
|
||||
}
|
||||
|
||||
public bool PlayYear()
|
||||
{
|
||||
var year = new Year(_country, _random, _io);
|
||||
|
||||
_io.Write(year.Status);
|
||||
|
||||
var result = year.GetPlayerActions() ?? year.EvaluateResults() ?? IsAtEndOfTerm();
|
||||
if (result.IsGameOver)
|
||||
{
|
||||
_io.WriteLine(result.Message);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Result IsAtEndOfTerm()
|
||||
=> _yearNumber == MaxTerm
|
||||
? Result.GameOver(EndCongratulations(MaxTerm))
|
||||
: Result.Continue;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{0} countrymen died of carbon-monoxide and dust inhalation
|
||||
@@ -0,0 +1 @@
|
||||
{0} countrymen died of starvation
|
||||
@@ -0,0 +1 @@
|
||||
{0} countrymen left the island.
|
||||
@@ -0,0 +1,3 @@
|
||||
also had your left eye gouged out!
|
||||
;have also gained a very bad reputation.
|
||||
;have also been declared national fink.
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
You have been thrown out of office and are now
|
||||
residing in prison.;
|
||||
You have been assassinated.
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
You were forced to spend {0} rallods on funeral expenses
|
||||
@@ -0,0 +1 @@
|
||||
Think again. You've only got {0} rallods in the treasury.
|
||||
@@ -0,0 +1 @@
|
||||
How many rallods will you distribute among your countrymen
|
||||
@@ -0,0 +1,4 @@
|
||||
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).
|
||||
@@ -0,0 +1,2 @@
|
||||
you harvested {0} sq. miles of crops.
|
||||
{1}making {2} rallods.
|
||||
@@ -0,0 +1 @@
|
||||
(Due to increased air and water pollution from foreign industry.)
|
||||
@@ -0,0 +1 @@
|
||||
{0} countrymen came to the island.
|
||||
@@ -0,0 +1 @@
|
||||
Do you want instructions
|
||||
@@ -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!
|
||||
@@ -0,0 +1 @@
|
||||
Of {0} sq. miles planted,
|
||||
@@ -0,0 +1 @@
|
||||
Sorry, but each countryman can only plant 2 sq. miles.
|
||||
@@ -0,0 +1 @@
|
||||
Sorry, but you've only {0} sq. miles of farm land.
|
||||
@@ -0,0 +1 @@
|
||||
Think again, You've only {0} rallods left in the treasury.
|
||||
@@ -0,0 +1 @@
|
||||
How many square miles do you wish to plant
|
||||
@@ -0,0 +1 @@
|
||||
Think again. You only have {0} rallods remaining.
|
||||
@@ -0,0 +1 @@
|
||||
How many rallods do you wish to spend on pollution control
|
||||
@@ -0,0 +1,112 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
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 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();
|
||||
|
||||
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() : "";
|
||||
|
||||
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
|
||||
{
|
||||
<= 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() => GetString();
|
||||
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();
|
||||
public static string SavedCountrymenPrompt => GetString();
|
||||
public static string SavedWorkersPrompt => GetString();
|
||||
public static string SavedLandPrompt => GetString();
|
||||
public static string SavedLandError => GetString();
|
||||
|
||||
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);
|
||||
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}'.");
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
How many countrymen
|
||||
@@ -0,0 +1,2 @@
|
||||
Come on, you started with 1000 sq. miles of farm land
|
||||
and 10,000 sq. miles of forest land
|
||||
@@ -0,0 +1 @@
|
||||
How many square miles of land
|
||||
@@ -0,0 +1 @@
|
||||
How much did you have in the treasury
|
||||
@@ -0,0 +1 @@
|
||||
How many workers
|
||||
@@ -0,0 +1 @@
|
||||
Come on, your term in office is only {0} years.
|
||||
@@ -0,0 +1 @@
|
||||
How many years had you been in office when interrupted
|
||||
@@ -0,0 +1,2 @@
|
||||
*** Think again. You only have {0} square miles of farm land.
|
||||
{1}
|
||||
@@ -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.)
|
||||
@@ -0,0 +1 @@
|
||||
How many square miles do you wish to sell to industry
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
King
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Decrease because {0}
|
||||
@@ -0,0 +1 @@
|
||||
You made {0} rallods from tourist trade.
|
||||
@@ -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.
|
||||
@@ -0,0 +1 @@
|
||||
{0} workers came to the country and
|
||||
@@ -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, "");
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
using System.Text;
|
||||
|
||||
namespace King;
|
||||
|
||||
internal class Year
|
||||
{
|
||||
private readonly Country _country;
|
||||
private readonly IRandom _random;
|
||||
private readonly IReadWrite _io;
|
||||
private readonly int _plantingCost;
|
||||
private readonly int _landValue;
|
||||
|
||||
private float _landSold;
|
||||
private float _rallodsDistributed;
|
||||
private float _landPlanted;
|
||||
private float _pollutionControlCost;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public string Status => _country.GetStatus(_landValue, _plantingCost);
|
||||
|
||||
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
|
||||
? null
|
||||
: Result.GameOver(Goodbye);
|
||||
}
|
||||
|
||||
public Result? EvaluateResults()
|
||||
{
|
||||
var rallodsUnspent = _country.Rallods;
|
||||
|
||||
_io.WriteLine();
|
||||
_io.WriteLine();
|
||||
|
||||
return EvaluateDeaths()
|
||||
?? EvaluateMigration()
|
||||
?? EvaluateAgriculture()
|
||||
?? EvaluateTourism()
|
||||
?? DetermineResult(rallodsUnspent);
|
||||
}
|
||||
|
||||
public Result? EvaluateDeaths()
|
||||
{
|
||||
var supportedCountrymen = _rallodsDistributed / 100;
|
||||
_citizenSupport = supportedCountrymen - _country.Countrymen;
|
||||
_starvationDeaths = -_citizenSupport;
|
||||
if (_starvationDeaths > 0)
|
||||
{
|
||||
if (supportedCountrymen < 50) { return Result.GameOver(EndOneThirdDead(_random)); }
|
||||
_io.WriteLine(DeathsStarvation(_starvationDeaths));
|
||||
}
|
||||
|
||||
var pollutionControl = _pollutionControlCost >= 25 ? _pollutionControlCost / 25 : 1;
|
||||
_pollutionDeaths = (int)(_random.Next((int)_country.IndustryLand) / pollutionControl);
|
||||
if (_pollutionDeaths > 0)
|
||||
{
|
||||
_io.WriteLine(DeathsPollution(_pollutionDeaths));
|
||||
}
|
||||
|
||||
_deaths = (int)(_starvationDeaths + _pollutionDeaths);
|
||||
if (_deaths > 0)
|
||||
{
|
||||
var funeralCosts = _deaths * 9;
|
||||
_io.WriteLine(FuneralExpenses(funeralCosts));
|
||||
|
||||
if (!_country.TrySpend(funeralCosts, _landValue))
|
||||
{
|
||||
_io.WriteLine(InsufficientReserves);
|
||||
}
|
||||
|
||||
_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);
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
private Result? EvaluateTourism()
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user