I think even the simplest solutions can and should be made modular and SOLID. Let's try to refactor your game to give you an idea how to begin...
We start with a city. A city can have different squares where a square is just a simple character/symbol.
class City : IEnumerable<Square>
{
private readonly List<Square> _squares = new List<Square>();
public void Add(Square square)
{
_squares.Add(square);
}
public IEnumerator<Square> GetEnumerator() => _squares.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
Each square has a position and a symbol. It's abstract so we can derive more concrete types from it.
abstract class Square
{
protected Square(string symbol, int x, int y)
{
Symbol = symbol;
X = x;
Y = y;
}
public string Symbol { get; }
public int X { get; }
public int Y { get; }
public override string ToString() => Symbol;
}
You seem to have two types currently. A building and a street so here they are:
abstract class Square
{
protected Square(string symbol, int x, int y)
{
Symbol = symbol;
X = x;
Y = y;
}
public string Symbol { get; }
public int X { get; }
public int Y { get; }
public override string ToString() => Symbol;
}
interface IUpgradable
{
void Upgrade();
}
abstract class Building : Square, IUpgradable
{
protected Building(string symbol, int x, int y, int level)
: base(symbol, x, y)
{
Level = level;
}
public int Level { get; private set; }
public void Upgrade()
{
Level++;
}
public override string ToString() => "O";
}
class School : Building
{
public School(int x, int y, int level) : base("H", x, y, level) {}
}
class Hospital : Building
{
public Hospital(int x, int y, int level) : base("S", x, y, level) {}
}
class Street : Square
{
public Street(int x, int y) : base("#", x, y) { }
public override string ToString() => "#";
}
Buildings can be upgraded thus the Upgrade
method which increases its level. Each upgradable type implements the IUpgradable
interface then so you can even filer on that.
I don't know how you generate your map but for the sake of this example I did it by hand:
Here's a simple city:
// ###
// #H#
// ###
var city = new City
{
new Street(0, 0), new Street(1, 0),new Street(2, 0),
new Street(0, 1), new Hospital(1, 1),new Street(2, 1),
new Street(0, 2), new Street(1, 2),new Street(2, 2),
}
Next we want to upgrade some buildings (I might have the condition for upgrading wrong but it should just demostrate the general idea)
Random r = new Random(seed);
// helper encapsulating the can-upgrade logic
var canUpgradeBuilding = new Func<Building, bool>(b => b.Level <= r.Next(0, 100));
// upgrading buildings
foreach (var b in city.OfType<Building>().Where(canUpgradeBuilding))
{
b.Upgrade();
}
r
should be a private readonly static field, not re-created every iteration. \$\endgroup\$