Pierwszy projekt w C#: Gra zgadywanka krok po kroku
Masz dość tutoriali typu Hello World i nie wiesz, jak zacząć prawdziwy projekt w C#?
W tym artykule pokażę Ci, jak zbudować działającą grę zgadywankę w C#, krok po kroku z poprawną architekturą, walidacją danych i czytelną strukturą kodu.
To nie jest kolejny tutorial do przepisania. To fundament pod realne projekty.
🎯 Dlaczego “Hello World” to za mało?
Większość kursów kończy się na:
Console.WriteLine("Hello World");
Problem? To nie jest aplikacja. To jedna instrukcja.
❌ Czego NIE uczysz się z Hello World
- zarządzania stanem aplikacji
- walidacji danych wejściowych
- logiki warunkowej
- struktury projektu
✅ Czego nauczysz się w tym projekcie
Budując grę, poznasz:
- pętle i kontrolę przepływu
- walidację inputu (
TryParse) - zarządzanie stanem
- separację odpowiedzialności
- podstawy architektury
🧱 Architektura – zanim napiszesz kod

Zamiast zaczynać od kodu – zaczynamy od modelu mentalnego.
Podziel aplikację na:
📦 GameState – magazyn danych
- przechowuje stan gry
- liczba do zgadnięcia
- liczba prób
- status gry
🤖 InputValidator – walidacja
- sprawdza czy input jest poprawny
- chroni aplikację przed błędami
🤖 GameLogic – logika
- sprawdza wynik
- decyduje o stanie gry
🎨 UIManager – prezentacja
- wyświetla dane
- zbiera input
👉 Zasada: każda klasa = jedna odpowiedzialność
🧩 Implementacja krok po kroku
🧱 Krok 1 – GameState (stan gry)
public class GameState
{
public int SecretNumber { get; private set; }
public int MaxAttempts { get; private set; }
public int AttemptsUsed { get; private set; }
public int AttemptsLeft => MaxAttempts - AttemptsUsed;
public bool IsGameWon { get; private set; }
public GameState(int maxAttempts = 7)
{
var random = new Random();
SecretNumber = random.Next(1, 101); // 1-100
MaxAttempts = maxAttempts;
AttemptsUsed = 0;
IsGameWon = false;
}
public void IncrementAttempt()
{
AttemptsUsed++;
}
public void MarkAsWon()
{
IsGameWon = true;
}
public bool IsGameOver()
{
return IsGameWon || AttemptsLeft == 0;
}
}
💡 Dlaczego to jest dobre?
- enkapsulacja (
private set) - brak “rozlanego stanu” po aplikacji
- kontrolowane zmiany przez metody
🤖 Krok 2 – InputValidator

public class InputValidator
{
public bool TryParseGuess(string input, out int guess)
{
guess = 0;
// Sprawdź czy to w ogóle liczba
if (!int.TryParse(input, out guess))
{
Console.WriteLine("❌ To nie jest liczba! Spróbuj ponownie.\n");
return false;
}
// Sprawdź zakres
if (guess < 1 || guess > 100)
{
Console.WriteLine("❌ Liczba musi być między 1 a 100!\n");
return false;
}
return true;
}
}
💡 Best practice
- używaj
TryParsezamiastParse - nie dopuszczaj do wyjątków w normalnym flow
🤖 Krok 3 – GameLogic

public class GameLogic
{
private readonly GameState _state;
public GameLogic(GameState state)
{
_state = state;
}
public GuessResult CheckGuess(int guess)
{
_state.IncrementAttempt();
if (guess == _state.SecretNumber)
{
_state.MarkAsWon();
return GuessResult.Correct;
}
else if (guess < _state.SecretNumber)
{
return GuessResult.TooLow;
}
else
{
return GuessResult.TooHigh;
}
}
}
// Enum dla wyników
public enum GuessResult
{
TooLow,
TooHigh,
Correct
}
💡 Dlaczego to jest ważne?
- Dependency Injection → testowalność
- brak tight coupling
- czysta logika biznesowa
🎨 Krok 4 – UIManager

public class UIManager
{
public void DisplayWelcome()
{
Console.Clear();
Console.WriteLine("🎮 === GRA ZGADYWANKA === 🎮\n");
Console.WriteLine("Wylosowałem liczbę od 1 do 100.");
Console.WriteLine("Spróbuj ją odgadnąć!\n");
}
public void DisplayAttemptPrompt(int attemptNumber, int attemptsLeft)
{
Console.WriteLine($"Próba {attemptNumber} (Pozostało: {attemptsLeft})");
Console.Write("Twoja liczba: ");
}
public void DisplayResult(GuessResult result, int attemptsUsed)
{
switch (result)
{
case GuessResult.TooLow:
Console.WriteLine("📊 Za mało! Spróbuj wyżej.\n");
break;
case GuessResult.TooHigh:
Console.WriteLine("📊 Za dużo! Spróbuj niżej.\n");
break;
case GuessResult.Correct:
Console.WriteLine($"\n🎉 GRATULACJE! Odgadłeś za {attemptsUsed} prób(y)!\n");
break;
}
}
public void DisplayGameOver(int secretNumber)
{
Console.WriteLine($"\n💀 PRZEGRAŁEŚ! Poprawna liczba to: {secretNumber}\n");
}
public bool AskPlayAgain()
{
Console.Write("Chcesz zagrać ponownie? (t/n): ");
string input = Console.ReadLine()?.ToLower();
return input == "t" || input == "tak";
}
}
💡 Separation of Concerns
UI nie podejmuje decyzji – tylko wyświetla.
🔄 Krok 5 – Main (składanie wszystkiego)

class Program
{
static void Main()
{
var ui = new UIManager();
var validator = new InputValidator();
bool playAgain = true;
while (playAgain)
{
// 1. Inicjalizacja magazynu
var gameState = new GameState(maxAttempts: 7);
var gameLogic = new GameLogic(gameState);
// 2. Powitanie
ui.DisplayWelcome();
// 3. Główna pętla gry
while (!gameState.IsGameOver())
{
// 3a. Prompt
ui.DisplayAttemptPrompt(
gameState.AttemptsUsed + 1,
gameState.AttemptsLeft
);
// 3b. Pobierz i waliduj input
string input = Console.ReadLine();
if (!validator.TryParseGuess(input, out int guess))
continue; // Powtórz próbę bez liczenia
// 3c. Sprawdź guess
var result = gameLogic.CheckGuess(guess);
// 3d. Wyświetl feedback
ui.DisplayResult(result, gameState.AttemptsUsed);
}
// 4. Koniec gry
if (!gameState.IsGameWon)
{
ui.DisplayGameOver(gameState.SecretNumber);
}
// 5. Restart?
playAgain = ui.AskPlayAgain();
}
}
}
💡 Co tu się dzieje?
To jest linia montażowa aplikacji:
- Pobierz dane
- Zwaliduj
- Przetwórz
- Wyświetl
🧪 Edge cases – o których większość zapomina

✔️ błędny input (abc)
✔️ liczba poza zakresem
✔️ brak prób
✔️ restart gry
👉 To jest różnica między:
- kodem demo
- a kodem produkcyjnym
🚀 Rozszerzenia (Level Up)

🟢 Easy
- poziomy trudności
- historia prób
🟡 Medium
- zapis wyniku do pliku
- system punktów
🔴 Hard
- AI (binary search)
- wersja GUI (WPF / Avalonia)
🔗 Zobacz też
- C# Podstawy Programowania: Twój Pierwszy Krok w Świat Kodowania
- AI w .NET: Zostań Architektem Inteligentnych Aplikacji!
- C# Clean Architecture w Praktyce
- C# – Zbuduj Własnego Tetrisa! Kompletny Przewodnik
- 7 Dniowe Wyzwanie C# Tic Tac Toe
- C# Zbuduj Profesjonalny Portal Randkowy od Podstaw!
📌 Podsumowanie
Zbudowałeś:
- działającą aplikację
- strukturę projektu
- separację odpowiedzialności
- obsługę edge case’ów
👉 To jest pierwszy realny projekt do portfolio.
📣 Call To Action
💬 Zostaw komentarz – co dodałeś do gry?
📥 Pobierz roadmapę (link przy zapisie na listę VIP)
Zobacz także — powiązane artykuły
👉 MCP w .NET (C#) – jak zbudować serwer AI krok po kroku
👉 Tworzenie klas i obiektów w C# — kompletny przewodnik
👉 Pattern Matching w C# – switch expressions i type patterns
Dołącz do Listy VIP
I otrzymaj roadmapę Junior .NET Developer oraz najlepszą ofertę, gdy tylko ruszą zapisy!!!

