오늘 배운 내용
- 리터럴
- var 키워드
- C# 2주차 강의 숙제 - 숫자 맞추기 게임
- C# 2주차 강의 숙제 - 틱택토 게임
- 클래스와 구조체의 차이점
- C# virtual, override
리터럴
C# 1주차 강의에서 변수에 대한 내용이 나오면 리터럴에 관한 내용도 나왔다.
리터럴
은 결국에는 컴퓨터에서 숫자나 문자를 어떻게 인식하는지에 대한 것이라고 생각했다.
예를 들어서 123 같은 경우에는 컴퓨터에서 이것을 정수로 인식하기 때문에 정수형 리터럴
asdf 같은 경우에는 어떤 특정한 의미나 값을 가지지 않는 단순한 문자라서 리터럴이 아니지만,
“abdsf” 같은 경우에는 따옴표로 둘러쌓여 있어서 string 타입으로 인식하기 때문에 문자열 리터럴
이 되는것이다.
그리고 모든 리터럴들은 결국 각자 고정된 값을 가진다고 생각할 수 있고, 우리는 변수에 이런 리터럴을 저장해서 데이터를 저장한다
var 키워드
변수를 선언할 때 명시적으로 형식을 지정하지 않고 var키워드를 사용하여 선언하면
컴파일러가 초기화식을 기반으로 변수의 데이터형식을 추론하여 형식을 지정한다.
그렇기 때문에 var키워드를 사용할 떄는 선언과 초기화를 동시에 해야한다.
var number = 130;
var numbers = new int[] {1,2,3,4,5};
var 키워드를 사용해서 코드의 가독성과 유연성을 높일 수 있다.
C# 2주차 강의 숙제 - 숫자 맞추기 게임
namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
Random ran = new Random();
int correctNum = ran.Next(1, 101);
Console.WriteLine("숫자 맞추기 게임을 시작합니다. 1~100 까지의 숫자 중 하나를 선택하세요.");
Console.Write("숫자를 입력하세요 : ");
int num;
int tryNum = 0;
while(true)
{
while (int.TryParse(Console.ReadLine(), out num) == false)
{
Console.Write("숫자를 입력하세요 : ");
}
tryNum++;
if (num == correctNum)
{
break;
}
else if (correctNum > num)
{
Console.WriteLine("너무 작습니다!");
}
else
{
Console.WriteLine("너무 큽니다!");
}
}
Console.WriteLine($"축하합니다! {tryNum}번 만에 숫자를 맞추셨습니다.");
}
}
}
C# 2주차 강의 숙제 - 틱택토 게임
일단 만들고 제대로 작동하는 것은 확인 했는데 숫자의 자리를 찾아서 하는 부분들을 하드 코딩 하지않는 더 좋은 다른 방법은 없었을까 생각했다.
내 코드는 세로줄, 가로줄 즉 게임판을 for 문으로 그려주기 위해서 각 숫자의 자리가 붙어있지 않게 되었고
그 때문에 숫자의 자리를 찾는 것을 하드 코딩 해야 했던것 같다.
게임판을 하드 코딩해서 그려준다면 숫자의 자리는 편하게 찾을 수 있다.
namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
// 한칸이 가로 5칸 세로 3칸이고 가운데에 숫자가 써진다.
// 2,3 2,9 2,15
// 6,3 6,9 6,15
// 10,3 10,9 10,15
// 가로 칸수 % 6 == 0 인 곳에는 세로줄이 생성된다.
// 세로 칸수 % 4 == 0 인 곳에는 가로줄이 생성된다.
// 맵은 5 x3 + 2 가로길이 17
// 3 x3 +2 세로길이 11
string[,] map = new string[12, 18]; // 가로줄 세로줄 계산을 위해서 인덱스 0을 버린다
List<int> player1Selected = new List<int>();
List<int> player2Selected = new List<int>();
bool isPlayer1 = true;
GameInit(map);
DrawScreen(map);
while (true)
{
if (isPlayer1)
{
int select;
int[] pos;
Console.Write("플레이어 1 님의 턴 입니다. 위치를 선택해 주세요 : ");
while(int.TryParse(Console.ReadLine(), out select) == false || NumToPos(select, out pos) && map[pos[0],pos[1]] != select.ToString())
{
Console.Write("위치를 다시 선택해 주세요 : ");
}
map[pos[0], pos[1]] = "X";
player1Selected.Add(select);
isPlayer1 = false;
}
else
{
int select;
int[] pos;
Console.Write("플레이어 1 님의 턴 입니다. 위치를 선택해 주세요 : ");
while (int.TryParse(Console.ReadLine(), out select) == false || NumToPos(select, out pos) && map[pos[0], pos[1]] != select.ToString())
{
Console.Write("위치를 다시 선택해 주세요 : ");
}
map[pos[0], pos[1]] = "O";
player2Selected.Add(select);
isPlayer1 = true;
}
DrawScreen(map);
if (CheckWin(player1Selected))
{
Console.WriteLine("플레이어 1 님의 승리 입니다!");
break;
}
if (CheckWin(player2Selected))
{
Console.WriteLine("플레이어 2 님의 승리 입니다!");
break;
}
if(player1Selected.Count == 5 && player2Selected.Count == 4)
{
Console.WriteLine("게임 결과는 무승부 입니다!");
break;
}
}
Console.WriteLine("게임을 종료 합니다.");
// 비기는 경우
}
static bool CheckWin(List<int> playerSelected)
{
if (playerSelected.Contains(1))
{
if (playerSelected.Contains(2) && playerSelected.Contains(3))
{
return true;
}
else if (playerSelected.Contains(4) && playerSelected.Contains(7))
{
return true;
}
else if (playerSelected.Contains(5) && playerSelected.Contains(9))
{
return true;
}
}
if (playerSelected.Contains(2))
{
if (playerSelected.Contains(5) && playerSelected.Contains(8))
{
return true;
}
}
if (playerSelected.Contains(3))
{
if (playerSelected.Contains(5) && playerSelected.Contains(7))
{
return true;
}
else if (playerSelected.Contains(6) && playerSelected.Contains(9))
{
return true;
}
}
if (playerSelected.Contains(4))
{
if (playerSelected.Contains(5) && playerSelected.Contains(6))
{
return true;
}
}
if (playerSelected.Contains(7) && playerSelected.Contains(8) && playerSelected.Contains(9)){
return true;
}
return false;
}
static bool NumToPos(int num, out int[] pos)
{
switch (num)
{
case 1:
pos = new int[] { 2, 3 };
break;
case 2:
pos = new int[] { 2, 9 };
break;
case 3:
pos = new int[] { 2, 15 };
break;
case 4:
pos = new int[] { 6, 3 };
break;
case 5:
pos = new int[] { 6, 9 };
break;
case 6:
pos = new int[] { 6, 15 };
break;
case 7:
pos = new int[] { 10, 3 };
break;
case 8:
pos = new int[] { 10,9 };
break;
case 9:
pos = new int[] { 10, 15 };
break;
default:
pos = new int[] { 0, 0 };
return false;
}
return true;
}
static void GameInit(string[,] map)
{
int num = 1;
for (int i = 1; i < 12; i++)
{
for (int j = 1; j < 18; j++)
{
if (j % 6 == 0)
{
map[i, j] = "I";
}
else if (i % 4 == 0)
{
map[i, j] = "-";
}
else if (i % 4 == 2 && j % 6 == 3)
{
map[i, j] = num++.ToString();
}
else
{
map[i, j] = " ";
}
}
}
}
static void DrawScreen(string[,] map)
{
Console.Clear();
Console.WriteLine("플레이어 1 : X 와 플레이어 2 : O");
for (int i = 1; i < 12; i++)
{
string answer = "";
for (int j = 1; j < 18; j++)
{
answer += map[i, j];
}
Console.WriteLine(answer);
}
}
}
}
클래스와 구조체의 차이점
클래스와 구조체의 가장 큰 차이점은 구조체
는 값 타입
으로 스택 메모리 영역
에 생성되고
클래스
는 참조 타입
으로 new 키워드를 사용해 힙 메모리 영역
에 객체를 생성하고 해당 객체를 참조하는 방식이다.
C# virtual, override
상속과 다형성에 대해서 공부하면서 그냥 오버라이딩과 virtual,override를 사용한 오버라이딩의 차이점을 알 수 있었다.
결론은 상위클래스의 메서드를 우선 시 하고싶으면 그냥 오버라이딩하고
하위 클래스의 메서드를 우선 시 하고싶으면 virtual과 override 키워드를 사용해서 오버라이딩 하면된다.
정리 :