This week's Code Review Weekend Challenge is about implementing a simple console game.
Here's my game loop:
class Program
{
static void Main(string[] args)
{
var player = new Player();
var intro = new IntroScreen(player);
var nextScreen = intro.Run();
while (nextScreen != null)
{
nextScreen = nextScreen.Run();
}
}
}
So I have a Player
class:
public class Player
{
public string Name { get; set; }
public ObservableCollection<InventoryItem> Inventory { get; private set; }
public Player()
{
Inventory = new ObservableCollection<InventoryItem>();
Inventory.CollectionChanged += Inventory_CollectionChanged;
}
private void Inventory_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action != NotifyCollectionChangedAction.Add) return;
foreach (InventoryItem item in e.NewItems)
{
Console.WriteLine("Received '{0}'!\n({1})", item.Name, item.Description);
}
Console.WriteLine();
Console.ReadLine();
}
public bool HasItem(string name)
{
return Inventory.Any(item => item.Name.ToLower() == name.ToLower());
}
}
The player has an Inventory
that's made up of InventoryItem
instances:
public struct InventoryItem
{
public string Name { get; set; }
public string Description { get; set; }
}
So the role of the Player
is really to carry an inventory, whatever that is; whenever an item is added to the player's inventory, there's an output to the console.
The game's mechanics are tucked inside a GameScreen
abstract class:
public abstract class GameScreen
{
protected IDictionary<string, Func<GameScreen>> MenuItems;
public abstract GameScreen Run();
protected void Write(string text)
{
Console.Write(text);
Console.WriteLine();
Console.WriteLine("[ENTER]");
Console.ReadLine();
}
protected string Prompt(string text)
{
Console.WriteLine(text);
var result = Console.ReadLine();
Console.WriteLine();
return result;
}
protected GameScreen Menu()
{
Console.WriteLine("What do you do?");
var i = 0;
foreach (var item in MenuItems)
{
i++;
Console.WriteLine("[{0}] {1}", i, item.Key);
}
Console.WriteLine();
Console.WriteLine("Selection?");
var input = Console.ReadLine();
int selection;
if (int.TryParse(input, out selection))
{
if (selection > 0 && selection <= MenuItems.Count)
{
return MenuItems.ElementAt(selection - 1).Value();
}
}
return null;
}
}
This is a tiny little game, here's the IntroScreen
and KitchenScreen
implementations:
public class IntroScreen : GameScreen
{
private readonly Player _player;
public IntroScreen(Player player)
{
MenuItems = new Dictionary<string,Func<GameScreen>>
{
{"Pick up empty bottles, chips and pretzels", () =>
{
MenuItems.Remove("Pick up empty bottles, chips and pretzels");
_player.Inventory.Add(new InventoryItem { Name = "Living Room badge", Description = "A badge that certifies the living room has been cleaned up." });
return this;
} },
{"Go to [KITCHEN]", () => new KitchenScreen(player) }
};
_player = player;
}
public override GameScreen Run()
{
Console.Clear();
if (!_player.HasItem("GREEN BAG")) return Intro();
return Menu();
}
private GameScreen Intro()
{
Write("You wake up with a headache, confused and\nsurrounded with empty bottles, chips and pretzels.");
Write("Ah! There you are! Time to clean up this mess!\nHere's a [GREEN BAG], meet you in the [KITCHEN] in 30 minutes!");
var bag = new InventoryItem { Name = "GREEN BAG", Description = "A general-purpose garbage bag." };
_player.Inventory.Add(bag);
var name = string.Empty;
int attempts = 0;
while (string.IsNullOrEmpty(name))
{
attempts++;
string prompt;
if (attempts == 1)
{
prompt = "You get up, pick up the bag and remember your name (enter it!):";
name = Prompt(prompt);
}
else if (attempts < 3)
{
prompt = "Uh, don't you remember your name?";
name = Prompt(prompt);
}
else
{
name = "Rudolph";
prompt = string.Format("Ok nevermind, we'll call you {0}.", name);
Write(prompt);
}
}
_player.Name = name;
return Menu();
}
}
public class KitchenScreen : GameScreen
{
private readonly Player _player;
public KitchenScreen(Player player)
{
MenuItems = new Dictionary<string, Func<GameScreen>>
{
{ "Go to [LIVING ROOM]", () => new IntroScreen(player) }
};
_player = player;
}
public override GameScreen Run()
{
Console.Clear();
if (_player.HasItem("Living Room badge"))
{
Write("You walk into the kitchen, your mom looks too happy.");
Write(_player.Name + ", finally! So you cleaned up everything! Great! So we're ready for NewYear's party!");
MenuItems = new Dictionary<string, Func<GameScreen>> { { "Collapse and wake up when the Holidays are over", () => null } };
}
else
{
Write("You walk into the kitchen, your mom is cleaning up dishes.");
Write(_player.Name + "! What are you doing here? I told you to clean up! Come back when you're done!");
}
return Menu();
}
}
Output:
You wake up with a headache, confused and surrounded with empty bottles, chips and pretzels.
[ENTER]
Ah! There you are! Time to clean up this mess! Here's a [GREEN BAG], meet you in the [KITCHEN] in 30 minutes!
[ENTER]
Received 'GREEN BAG'!
(A general-purpose garbage bag.)
You get up, pick up the bag and remember your name (enter it!):
Uh, don't you remember your name?
Ok nevermind, we'll call you Rudolph.
[ENTER]
What do you do?
[1] Pick up empty bottles, chips and pretzels
[2] Go to [KITCHEN]
Selection?
2
You walk into the kitchen, your mom is cleaning up dishes.
[ENTER]
Rudolph! What are you doing here? I told you to clean up! Come back when you're
done!
[ENTER]
What do you do?
[1] Go to [LIVING ROOM]
Selection?
1
What do you do?
[1] Pick up empty bottles, chips and pretzels
[2] Go to [KITCHEN]
Selection?
1
Received 'Living Room badge'!
(A badge that certifies the living room has been cleaned up.)
What do you do?
[1] Go to [KITCHEN]
Selection?
1
You walk into the kitchen, your mom looks too happy.
[ENTER]
Rudolph, finally! So you cleaned up everything! Great! So we're ready for NewYear's party!
[ENTER]
What do you do?
[1] Collapse and wake up when the Holidays are over
Selection?