snippetcsharpMinor
Generate Buildings in City
Viewed 0 times
citygeneratebuildings
Problem
I am developing a game, its map is based on a 2D city. The city is being generated as string,
Here is an example:
Now I am replacing the
Currently I am doing it like this:
Is there a more elegant way to do this? In the best case, this would be achieved by using no loops at all, but I am struggling with LINQ a bit.
# are streets, O are buildings.Here is an example:
#######
#OOOOO#
#OOOOO#
#######
#OOOOO#
#OOOOO#
#######Now I am replacing the
Os with other buildings, by replacing the character with an other. The other buildings are defined in a dictionary, where the identifying character is the key and the value is a number between 1 and 100 which is the propability of the building to replace an O.Currently I am doing it like this:
// Turn city into charArray
char[] cityChars = renderedCity.ToCharArray();
// Cycle through all KeyValuePairs, ordered by Value ascending
foreach (KeyValuePair kvp in specialBuildings.OrderBy(key => key.Value))
{
Random r = new Random(seed);
// Do the following for all normal buildings in the city
// If a random seeded number is smaller or equal to the propability of the spawn, change the building into the new one
cityChars = cityChars.Select(c => c == 'O' ? (r.Next(0, 100) <= kvp.Value ? kvp.Key : c) : c).ToArray();
}Is there a more elegant way to do this? In the best case, this would be achieved by using no loops at all, but I am struggling with LINQ a bit.
Solution
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.
Each square has a position and a symbol. It's abstract so we can derive more concrete types from it.
You seem to have two types currently. A building and a street so here they are:
Buildings can be upgraded thus the
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:
Next we want to upgrade some buildings (I might have the condition for upgrading wrong but it should just demostrate the general idea)
We start with a city. A city can have different squares where a square is just a simple character/symbol.
class City : IEnumerable
{
private readonly List _squares = new List();
public void Add(Square square)
{
_squares.Add(square);
}
public IEnumerator 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(b => b.Level ().Where(canUpgradeBuilding))
{
b.Upgrade();
}Code Snippets
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();
}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;
}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() => "#";
}// ###
// #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),
}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();
}Context
StackExchange Code Review Q#138578, answer score: 2
Revisions (0)
No revisions yet.