<aside> 💡 Notion 팁: 새 페이지를 만들고 템플릿 목록에서 데일리 일기를 선택해 매일 아래 양식을 자동으로 생성할 수 있어요.

</aside>

오늘은 무엇을 배웠나요

  1. C# 문법 종합반 3주차 과제

이야깃거리

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

public class Point
{
    public int x { get; set; }
    public int y { get; set; }
    public char sym { get; set; }

    public Point(int _x, int _y, char _sym)
    {
        x = _x;
        y = _y;
        sym = _sym;
    }

    public void Draw()
    {
        Console.SetCursorPosition(x, y);
        Console.Write(sym);
    }

    public void Clear()
    {
        sym = ' ';
        Draw();
    }
}

public class Snake
{
    private List<Point> body;
    private Direction direction;

    public Snake(Point tail, int length, Direction _direction)
    {
        body = new List<Point>();
        direction = _direction;

        for (int i = 0; i < length; i++)
        {
            Point p = new Point(tail.x + i, tail.y, '*');
            body.Add(p);
        }
    }

    public void Move()
    {
        Point tail = body.Last();
        Point head = GetNextPoint();
        body.Insert(0, head);
        body.RemoveAt(body.Count - 1);
    }

    public Point GetNextPoint()
    {
        Point head = body.First();
        Point nextPoint = new Point(head.x, head.y, head.sym);
        nextPoint.Move(direction);
        return nextPoint;
    }

    public void HandleKey(ConsoleKey key)
    {
        if (key == ConsoleKey.LeftArrow && direction != Direction.RIGHT)
            direction = Direction.LEFT;
        else if (key == ConsoleKey.RightArrow && direction != Direction.LEFT)
            direction = Direction.RIGHT;
        else if (key == ConsoleKey.UpArrow && direction != Direction.DOWN)
            direction = Direction.UP;
        else if (key == ConsoleKey.DownArrow && direction != Direction.UP)
            direction = Direction.DOWN;
    }

    public void Draw()
    {
        foreach (Point p in body)
        {
            p.Draw();
        }
    }

		public void Move(Direction direction)
		{
		    // 방향에 따라 x 또는 y 좌표를 조정하여 이동
		    if (direction == Direction.LEFT)
		        x--;
		    else if (direction == Direction.RIGHT)
		        x++;
		    else if (direction == Direction.UP)
		        y--;
		    else if (direction == Direction.DOWN)
		        y++;
		}
}

public enum Direction
{
    LEFT,
    RIGHT,
    UP,
    DOWN
}

class Program
{
    static void Main()
    {
        Console.SetWindowSize(80, 25);
        Console.SetBufferSize(80, 25);

        Point tail = new Point(4, 5, '*');
        Snake snake = new Snake(tail, 4, Direction.RIGHT);

        while (true)
        {
            if (Console.KeyAvailable)
            {
                ConsoleKeyInfo key = Console.ReadKey();
                snake.HandleKey(key.Key);
            }

            snake.Move();
            Console.Clear();
            snake.Draw();
            Thread.Sleep(100);
        }
    }
}

우선 먹이를 먹는 건 제쳐두고 뱀이 키보드 방향 키 입력을 받으면 콘솔 창에서 움직이도록 해보았다. 이 코드대로 하면 뱀이 잘 움직이는데, 콘솔 화면 밖으로 나갔을 때 OutOfRangeException이 발생하여 예외처리가 필요한 것과, 뱀의 속도가 너무 빨라 Thread.Sleep(); 값을 100보다 크게 설정해야 할 것 같다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

public class Point
{
		...
    public bool IsHitWall(int maxX, int maxY)
    {
        return x <= 0 || x >= maxX || y <= 0 || y >= maxY;
    }
}

public class Snake
{
    private List<Point> body;
    private Direction direction;
    private int maxX;
    private int maxY;

    public Snake(Point tail, int length, Direction _direction, int _maxX, int _maxY)
    {
        body = new List<Point>();
        direction = _direction;
        maxX = _maxX;
        maxY = _maxY;

        for (int i = 0; i < length; i++)
        {
            Point p = new Point(tail.x + i, tail.y, '*');
            body.Add(p);
        }
    }

		...

    public bool IsGameOver()
    {
        return body.Any(p => p.IsHitWall(maxX, maxY));
    }
}

public enum Direction
{
    LEFT,
    RIGHT,
    UP,
    DOWN
}

class Program
{
    static void Main()
    {
        Console.SetWindowSize(80, 25);
        Console.SetBufferSize(80, 25);

        Point tail = new Point(4, 5, '*');
        int maxX = Console.WindowWidth;
        int maxY = Console.WindowHeight;
        Snake snake = new Snake(tail, 4, Direction.RIGHT, maxX, maxY);

        while (true)
        {
						...

            Console.Clear();
            snake.Draw();
            Thread.Sleep(300); // 이동 속도 조절을 위해 100보다 작은 값으로 수정 가능
        }
    }
}

다음과 같이 수정하여 뱀의 속도를 조절하고 뱀이 콘솔창 외곽(벽)에 닿았을 때 게임오버 되도록 했다.

이제 남은 건 먹이 구현이다.

public class Snake
{
		...

    public bool Eat(Point food)
    {
        Point head = GetNextPoint();
        if (head.IsHit(food))
        {
            food.Clear();
            food = null;
            return true;
        }
        return false;
    }
}

public class FoodCreator
{
    private int mapWidth;
    private int mapHeight;
    private char sym;

    private Random random = new Random();

    public FoodCreator(int mapWidth, int mapHeight, char sym)
    {
        this.mapWidth = mapWidth;
        this.mapHeight = mapHeight;
        this.sym = sym;
    }

    public Point CreateFood()
    {
        int x = random.Next(1, 81); // X 좌표 범위를 1부터 80까지로
        int y = random.Next(1, 21); // Y 좌표 범위를 1부터 20까지로
        return new Point(x, y, sym);
    }
}

...

class Program
{
    static void Main()
    {
        ...

        FoodCreator foodCreator = new FoodCreator(80, 20, '$');
        Point food = foodCreator.CreateFood();
        food.Draw();

        while (true)
        {
						...

            if (snake.Eat(food))
            {
                food = foodCreator.CreateFood();
                food.Draw();
            }

						...

            food.Draw();

            ...
        }
    }
}

위의 코드를 추가하여 (80, 20)의 범위 내에서 먹이가 $ 표시로 랜덤하게 생성되도록 하고, 뱀이 먹이를 먹으면 먹이가 없어지고 다른 곳에 생성되도록 했다. (생각보다 뱀이 가늘어서 먹이 먹기가 쉽지않다 🐍)

다음으로는 먹은 먹이의 수를 콘솔 창에 표시하려고 했는데,

public class Snake
{
    private List<Point> body;
    private Direction direction;
    private int maxX;
    private int maxY;
    int foodCount = 0;

		...

    public void IncreaseFoodCount()
    {
        foodCount++;
    }

    public int GetFoodCount()
    {
        return foodCount;
    }
}

...

class Program
{
    static void Main()
    {
        ...

        while (true)
        {
            if (Console.KeyAvailable)
            {
                ConsoleKeyInfo key = Console.ReadKey();
                snake.HandleKey(key.Key);
            }

            Console.SetCursorPosition(0, 0);
            Console.Write("먹은 음식의 수 : " + snake.GetFoodCount());

            snake.Move();

            if (snake.Eat(food))
            {
                snake.IncreaseFoodCount();
                food = foodCreator.CreateFood();
                food.Draw();
            }

            if (snake.IsGameOver())
            {
                Console.Clear();
                Console.SetCursorPosition(35, 12);
                Console.Write("Game Over");
                break;
            }

            Console.Clear();
            snake.Draw();
            food.Draw();

            Thread.Sleep(300); // 이동 속도 조절을 위해 100보다 작은 값으로 수정 가능

        }
    }
}

이렇게 했는데도 먹은 음식의 수가 콘솔 창에 출력되지 않았다.