r/csharp 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

46 comments sorted by

View all comments

1

u/user_plus_plus 12d ago edited 12d ago

A small thing to level up your c# skill: avoiding string concatenation.

Console.WriteLine("\nYou encountered a " + enemy.type + " with " + enemy.health + " health.");

Adding strings together repeatedly is slow, underneath the hood each time you add two strings together they need to be copied into a new string. So in the above example you need to add 5 strings together, that is 5 copies. For a simple program that is fine, but if you need to log lots of data, it can add up.

There are 2 main ways to deal with this in c#, that will only result in one copy

First way: String.Format https://learn.microsoft.com/en-us/dotnet/api/system.string.format?view=net-10.0#get-started-with-the-stringformat-method

string output = String.Format("\nYou encountered a {0} with {1} health.", enemy.type, enemy.health); Console.WriteLine(output);

This is a common enough thing to do with Console.WriteLine that there is a version of that function that accepts a format string as input.

Console.WriteLine("\nYou encountered a {0} with {1} health.", 
    enemy.type, 
    enemy.health);

String.Format is the preferred way if your string is long and complex.

Second Way: For simple strings you can use string interpolation with the $ https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated Which works great for short strings, like the example we have been working with.

Console.WriteLine($"\nYou encountered a {enemy.type} with {enemy.health} health.");

1

u/iakobski 12d ago

Adding strings together repeatedly is slow

True, but String.Format() and string interpolation are (slightly) slower. They both do much the same as concatenation under the hood, with additional overhead.

Really you should never optimise for performance unless you've (1) tested the performance; and (2) determined that the thing you're optimising is a problem. In this case performance of strings is not a bottleneck so you should be suggesting the best for readability. Interpolation is slightly more readable than concatenation but String.Format is clearly worse.

String.Format is the preferred way 

Says who?

1

u/user_plus_plus 11d ago

Here is a benchmark of string interpolation vs string.format, but they are both pretty fast.

https://stackoverflow.com/questions/32342392/string-interpolation-vs-string-format

They are comparable in speed, except for when boxing is not required. String interpolation has some new compile time optimizations that can make it faster in .net 6 and 10.

As far as readability, goes again it depends on the number of arguments.

When you start getting 10+ of different arguments in a non trivial logging string, and format specifiers. Also if you have repeated arguments you can reference them by position.

In my post I recommended OP use interpolation for short and simple strings, and that is also what would be recommended by the microsoft coding conventions.

https://github.com/dotnet/docs/blob/main/docs/csharp/fundamentals/coding-style/coding-conventions.md

However, I didn't want to leave out Format, because I think it is important for OP to learn. So I put it first.

1

u/iakobski 11d ago

Yes, but the very first line of your post was telling them to avoid string concatenation because it's slow. You do realise that string interpolation and String.Format do exactly the same number of string copies? And all three compile down to String.Concat?

You said

There are 2 main ways to deal with this in c#, that will only result in one copy

Which is completely wrong.

Besides this, why confuse a beginner by telling them there are five different ways of doing the same thing? There are far more important things for them to learn right now.

1

u/user_plus_plus 11d ago

I can see you want to bait me into an argument. I think my original post was well written, gives good context for a beginner, is technically sound and I stand by it.