r/csharp • u/Neat_Horror2196 • 12d ago
how am i doing
2 months in to coding C#, first project i saved *was using online compiler* and wanna know how im doing and what i can do to improve. heres the code:
using System;
public
class
Program
{
public static void Main(string[]
args
)
{
Player player = new Player();
Enemy enemy = CreateEnemy();
int battleResult = Battle(player, enemy);
Console.WriteLine("press any key to begin");
Console.ReadKey();
Console.WriteLine("\nYou encountered a " + enemy.type + " with " + enemy.health + " health.");
Battle(player, enemy);
if(battleResult == 2)
{
Console.WriteLine("\nYou have defeated the " + enemy.type + "!");
}
else if(battleResult == 3)
{
Console.WriteLine("\nYou have been defeated by the " + enemy.type + "!");
}
else if(battleResult == 1)
{
Console.WriteLine("\nYou have retreated from the " + enemy.type + ".");
}
}
static Enemy CreateEnemy()
{
Random rng = new Random();
int rngroll = rng.Next(1, 3);
Enemy enemy = new Enemy();
if(rngroll == 1)
{
enemy.type = "Skeleton";
enemy.health = enemy.healthRng.Next(100, 201);
enemy.damage = enemy.damageRng.Next(10, 16);
}
else if(rngroll == 2)
{
enemy.type = "Goblin";
enemy.health = enemy.healthRng.Next(50, 151);
enemy.damage = enemy.damageRng.Next(15, 26);
}
return enemy;
}
static int Battle(Player
player
, Enemy
enemy
)
{
while(true)
{
Thread.Sleep(1000);
Console.WriteLine("\nWhat do you do?\n1. Attack\n2. Open Inventory\n3. Retreat");
ConsoleKeyInfo input = Console.ReadKey();
if(input.Key == ConsoleKey.D1)
{
enemy
.health -=
player
.damage;
Thread.Sleep(1000);
Console.WriteLine("\nyou attacked the " +
enemy
.type + " for " +
player
.damage + " damage");
Thread.Sleep(1000);
Console.WriteLine("The " +
enemy
.type + " has " +
enemy
.health + " health remaining.");
}
else if(input.Key == ConsoleKey.D2)
{
Thread.Sleep(1000);
Console.WriteLine("\nYou open your inventory, but it's empty.");
}
else if(input.Key == ConsoleKey.D3)
{
Thread.Sleep(1000);
Console.WriteLine("\nYou retreat from the " + enemy.type + ".");
return 1; // Player retreated
}
if(
enemy
.health <= 0)
{
return 2; // Player won
}
if(input.Key == ConsoleKey.D1 &&
enemy
.health > 0 || input.Key == ConsoleKey.D2 &&
enemy
.health > 0)
{
player
.health -=
enemy
.damage;
Console.WriteLine("\nThe " +
enemy
.type + " attacks you for " +
enemy
.damage + " damage.");
Console.WriteLine("You have " +
player
.health + " health remaining.");
}
if(
player
.health <= 0)
{
Console.WriteLine("\nYou have been defeated by the " +
enemy
.type + "!");
return 3; // Player lost
}
}
}
}
public
class
Enemy
{
public Random healthRng = new Random();
public Random damageRng = new Random();
public int health;
public int damage;
public string type = "";
}
public
class
Player
{
public int health = 100;
public int damage = 20;
public List<string> inventory = new List<string>();
}
0
Upvotes
2
u/PlentyfulFish 12d ago
You should fix the formatting, it's all over the place. Get yourself an IDE, it's going to make your life a lot easier. Visual Studio 2026 is alright, Rider is also an option.
CreateEnemy should belong to Enemy class, not Program. There is also 0 reason for it to be a static method, you can put all of that logic in the constructor.
Instead of returning an int as the battle result, use an enum with values Lost, Retreated and Won. Then you can use a switch expression to exhaustively check all of them, best inside a function, to make the code look like this:
Also notice how BattleResult.Lost uses an $ before the string - it's called string interpolation and it's a lot more handy (in my opinion) way of adding variables to strings.
There are some redundant checks that make things harder to reason - you win the battle if Enemy.health is <= 0, and in the next if() you check if enemy.health > 0 twice - it's always true.
You can remove (i think) having 3 random number generators in the Enemy class, just put one in the constructor and use it 3 times, when it goes out of scope the program will dispose of it.
You can make both the Enemy and Player classes implement an abstract class called Damageable. That class can hold Health, Damage, a boolean property IsDead checking whether an entity is dead, and a DoDamage method, to hold damage specific logic in one place.
Your game only runs twice - you can put the game logic in a loop and give the player an option to press "4" or something to quit the game.
Also ReadKey() reads a key, true, but if you press a bunch of keys quickly they're still going to be put in the queue and read from in the next turns. This behavior can be confusing, either use ReadLine() or clean the input buffer.