c# 강의/과제

20200505 - winForm + 2048 게임 만들기

쪼혀 2020. 5. 4. 17:25

> 후기

- winfrom 을 스터디 하고 싶었던 차에 2048을 winfrom으로 만들어보기로 했다.

- 역시 마쏘는 어마어마한 형들이다.  사용하기 쉽게? 만든느낌을 받으며 적용시킬수 있었다.

- 아카데미시절 눈물나게했던,  JAVA Swing.. 요놈으로 게임만들어본 경험이 큰도움이 됬다.

- 아무래도 수학적인 머리가 부족해서, 2차원배열 정렬하는데, 애좀 먹었다. ㄷㄷ 

- 특히 좌우 정렬 공간지각능력 부족인가 ㅜㅜ

- 자바스크립트의 forEach 관련 메소드들이 있엇다면 좀더 쉽게 했을텐데, 머리가 나쁘면 몸이 고생하는것 을 다시 느꼈다.

- 스코어 누적은 잘되는지, 2048만들어서 클리어 해봐야하는데 검증 할 기력이 없다. ㄷㄷ

- 개똥같읕 코드로 반복문과 분기문이 아주 지저분한데, 가볍게 잘돌아가는것 같아 신기했다. 

 

> 실행파일

lioncho_2048.exe
0.15MB

 

> 게임 이미지

더보기
시작 화면

 

스코어 및 연산

 

칸 다차면 종료

 

 

> code

더보기
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace _20200502
{
    public partial class form : Form
    {
        Random random;

        int[,] array;
        bool start = true;
        int totalScore;

        int x;
        int y;
        int randomNum1;
        int randomNum2;

        Control newNumTemp;


        public form()
        {
            InitializeComponent();

            this.Init();
            this.StartGame();

            this.TableInit();

            this.IsNumberBackgroundColor();

        }

        public void Init()
        {
            this.random = new Random();
            this.newNumTemp = new Control();
        }

        // up 버튼 입력시 해당 방향으로 재정렬
        public void UpDataSort()
        {
            int[,] newArr = new int[4, 4];

            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    if (this.array[i, j] > 0)
                    {
                        for (int k = 0; k < newArr.GetLength(1); k++)
                        {
                            if (newArr[k, j] == 0)
                            {
                                if (k != 0)
                                {
                                    if (newArr[k - 1, j] == this.array[i, j])
                                    {
                                        newArr[k - 1, j] = this.array[i, j] * 2;
                                        this.totalScore += newArr[k - 1, j];
                                        break;
                                    }
                                }
                                newArr[k, j] = this.array[i, j];
                                break;
                            }
                        }
                    }
                }
            }
            this.array = newArr;
        }

        //ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

        // down 버튼 입력시 해당 방향으로 재정렬
        public void DownDataSort()
        {
            int[,] newArr = new int[4, 4];


            for (int i = 3; i >= 0; i--)
            {
                for (int j = 3; j >= 0; j--)
                {
                    if (this.array[i, j] > 0)
                    {
                        for (int k = 3; k >= 0; k--)
                        {
                            if (newArr[k, j] == 0)
                            {
                                if (k != 3)
                                {
                                    if (newArr[k + 1, j] == this.array[i, j])
                                    {
                                        newArr[k + 1, j] = this.array[i, j] * 2;
                                        this.totalScore += newArr[k + 1, j];
                                        break;
                                    }
                                }
                                newArr[k, j] = this.array[i, j];
                                break;
                            }
                        }
                    }
                }
            }
            this.array = newArr;
        }

        //ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

        // left 버튼 입력시 해당 방향으로 재정렬
        public void LeftDataSort()
        {
            int[,] newArr = new int[4, 4];

            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    // 값있을 경우
                    if (this.array[j, i] > 0)
                    {

                        // 행 
                        for (int k = 0; k < newArr.GetLength(1); k++)
                        {

                            if (newArr[j, k] == 0)
                            {
                                if (k != 0)
                                {
                                    if (newArr[j, k - 1] == this.array[j, i])
                                    {
                                        newArr[j, k - 1] = this.array[j, i] * 2;
                                        this.totalScore += newArr[j, k - 1];
                                        break;
                                    }
                                }
                                newArr[j, k] = this.array[j, i];
                                break;
                            }
                        }
                    }
                }
            }
            this.array = newArr;
        }

        //ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

        // right 버튼 입력시 해당 방향으로 재정렬
        public void RightDataSort()
        {
            int[,] newArr = new int[4, 4];

            for (int i = 3; i >= 0; i--)
            {
                for (int j = 0; j < 4; j++)
                {
                    // 값있을 경우
                    if (this.array[j, i] > 0)
                    {
                        // 행 
                        for (int k = 3; k >= 0; k--)
                        {

                            if (newArr[j, k] == 0)
                            {
                                if (k != 3)
                                {
                                    if (newArr[j, k + 1] == this.array[j, i])
                                    {
                                        newArr[j, k + 1] = this.array[j, i] * 2;
                                        this.totalScore += newArr[j, k + 1];
                                        break;
                                    }
                                }
                                newArr[j, k] = this.array[j, i];
                                break;
                            }
                        }
                    }
                }
            }
            this.array = newArr;
        }

        //ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

        // 뷰테이블에 있는 데이터, 로직 배열과 동기화
        public void TableInit()
        {
            this.array = new int[4, 4];

            foreach (Control ctrl in tableLayoutPanel1.Controls)
            {
                if (ctrl is Label)
                {
                    var row = tableLayoutPanel1.GetRow(ctrl);
                    var col = tableLayoutPanel1.GetColumn(ctrl);

                    this.array[row, col] = 0;

                    // 값 있는 경우
                    if (ctrl.Text.Length > 0)
                    {
                        int myNum = int.Parse(ctrl.Text);
                        this.array[row, col] = myNum;
                    }
                }
            }
            this.IsNumberBackgroundColor();
        }


        // 뷰 라벨 테이블 비우고 데이터 배열 초기화
        public void NewTable()
        {
            foreach (Control ctrl in tableLayoutPanel1.Controls)
            {
                if (ctrl is Label)
                {
                    ctrl.Text = "";
                }
            }
            this.array = new int[4, 4];
        }

        // 게임 스타트시 초기값 발생
        public void StartGame()
        {
            this.RandomXY();
            this.RandomNum();
            tableLayoutPanel1.GetControlFromPosition(y, x).Text = randomNum2.ToString();

            this.RandomXY();
            this.RandomNum();
            tableLayoutPanel1.GetControlFromPosition(y, x).Text = randomNum1.ToString();
        }

        // 처음에 주어지는 숫자 위치 정하기
        public void RandomXY()
        {
            // 낮은 확률로 처음 주어지는 숫자 위치 중첩 방지
            while (true)
            {
                int tempX = random.Next(0, 4);
                int tempY = random.Next(0, 4);

                if (this.x != tempX && this.y != tempY)
                {
                    this.x = tempX;
                    this.y = tempY;
                    break;
                }
            }
        }


        // 처음에 주어지는 숫자 2,4 난수 발생 로직
        public void RandomNum()
        {
            while (true)
            {
                int tempNum1 = random.Next(2, 5);
                int tempNum2 = random.Next(2, 5);

                bool cheeck1 = false;
                bool cheeck2 = false;

                // 처음만 두개의 숫자 발생
                if (this.start)
                {
                    if (tempNum2 == 2 || tempNum2 == 4)
                    {
                        this.randomNum1 = tempNum2;
                        cheeck1 = true;
                    }
                }

                if (tempNum1 == 2 || tempNum1 == 4)
                {
                    this.randomNum2 = tempNum1;
                    cheeck2 = true;
                }

                if (cheeck1 && cheeck2)
                {
                    break;
                }
            }

        }

        // 턴 이후 지급되는 랜덤 숫자 생성
        public void CreateNewNum()
        {
            while (true)
            {
                this.RandomXY();
                if (this.array[this.x, this.y] == 0)
                {
                    break;
                }
            }
            this.newNumTemp.ForeColor = Color.Black;
            this.RandomNum();
            this.array[this.x, this.y] = this.randomNum2;
            tableLayoutPanel1.GetControlFromPosition(y, x).Text = this.randomNum2.ToString();

            tableLayoutPanel1.GetControlFromPosition(y, x).ForeColor = Color.IndianRed;

            this.newNumTemp = tableLayoutPanel1.GetControlFromPosition(y, x);

            logBox.Items.Add($"신규랜덤난수:[{x},{y}]:{this.randomNum2}");
        }



        // new버튼 이벤트 발생시 초기화
        public void GameReset()
        {
            this.array = new int[4, 4];
            this.start = true;
            this.totalScore = 0;


            this.ViewReset();
            this.StartGame();
            this.TableInit();
            this.SetScoreView();
        }

        // 전체 테이블 라벨 지우고, log창 지우기
        public void ViewReset()
        {
            foreach (Control ctrl in tableLayoutPanel1.Controls)
            {
                if (ctrl is Label)
                {
                    ctrl.Text = "";
                }
            }
            logBox.Items.Clear();
        }

        // sort된 배열, 뷰 테이블라벨에 재적용
        public void UpdateView()
        {
            foreach (Control ctrl in tableLayoutPanel1.Controls)
            {
                if (ctrl is Label)
                {
                    var row = tableLayoutPanel1.GetRow(ctrl);
                    var col = tableLayoutPanel1.GetColumn(ctrl);
                    ctrl.Text = "";

                    // 값 있는 경우
                    if (this.array[row, col] > 0)
                    {
                        ctrl.Text = this.array[row, col].ToString();
                    }
                }
            }
        }

        // 빈배열 있는지 체크
        public bool EndGameCheck()
        {
            foreach (var item in this.array)
            {
                if (item == 0)
                {
                    return true;
                }
            }
            return false;
        }

        // 게임 클리어 체크
        public bool ClearGameCheck()
        {
            foreach (var item in this.array)
            {
                if (item.Equals(2048))
                {
                    return true;
                }
            }
            return false;
        }

        // 연산값에 대한 뷰 컬러처리
        public void IsNumberBackgroundColor()
        {
            int checkNum = 0;
            foreach (Control ctrl in tableLayoutPanel1.Controls)
            {
                if (ctrl is Label)
                {
                    ctrl.BackColor = Color.Gainsboro;

                    if (ctrl.Text != "")
                    {
                        checkNum = int.Parse(ctrl.Text);

                        if (checkNum == 8)
                        {
                            ctrl.ForeColor = Color.WhiteSmoke;
                            ctrl.BackColor = Color.LightSalmon;
                        }
                        else if (checkNum == 16)
                        {
                            ctrl.ForeColor = Color.WhiteSmoke;
                            ctrl.BackColor = Color.LightCoral;
                        }
                        else if (checkNum == 32)
                        {
                            ctrl.ForeColor = Color.WhiteSmoke;
                            ctrl.BackColor = Color.Coral;
                        }
                        else if (checkNum >= 64)
                        {
                            ctrl.ForeColor = Color.WhiteSmoke;
                            ctrl.BackColor = Color.Tomato;
                        }
                        else
                        {
                            ctrl.BackColor = Color.Silver;
                            ctrl.ForeColor = Color.Black;
                        }
                    }

                    if (ctrl.Text == "")
                    {
                        ctrl.BackColor = Color.Silver;
                        ctrl.ForeColor = Color.Black;
                    }
                }
            }
        }

        // 스코어 뷰에 누계 적용
        public void SetScoreView()
        {
            scoreLabel.Text = this.totalScore.ToString();
        }

        // 개발시 배열 확인용 매소드
        public void ArrayPrint()
        {
            for (int i = 0; i < this.array.GetLength(0); i++)
            {
                for (int j = 0; j < this.array.GetLength(1); j++)
                {
                    Console.Write("[{0}, {1}]:{2} ㅣ", i, j, this.array[i, j]);
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        }

        //ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ 방향킼 버튼 이벤트 리스너 ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
        private void UpBtn_Click(object sender, EventArgs e)
        {
            if (ClearGameCheck()) { MessageBox.Show("게임 클리어!!"); }
            if (EndGameCheck())
            {
                this.UpDataSort();
                this.UpdateView();
                this.CreateNewNum();
                this.IsNumberBackgroundColor();
                this.SetScoreView();
            }
            else
            {
                MessageBox.Show("게임 종료");
            }
        }

        private void DownBtn_Click(object sender, EventArgs e)
        {
            if (ClearGameCheck()) { MessageBox.Show("게임 클리어!!"); }
            if (EndGameCheck())
            {
                this.DownDataSort();
                this.UpdateView();
                this.CreateNewNum();
                this.IsNumberBackgroundColor();
                this.SetScoreView();
            }
            else
            {
                MessageBox.Show("게임 종료");
            }
        }

        private void LeftBtn_Click(object sender, EventArgs e)
        {
            if (ClearGameCheck()) { MessageBox.Show("게임 클리어!!"); }
            if (EndGameCheck())
            {
                this.LeftDataSort();
                this.UpdateView();
                this.CreateNewNum();
                this.IsNumberBackgroundColor();
                this.SetScoreView();
            }
            else
            {
                MessageBox.Show("게임 종료");
            }
        }

        private void RightBtn_Click(object sender, EventArgs e)
        {
            if (ClearGameCheck()) { MessageBox.Show("게임 클리어!!"); }
            if (EndGameCheck())
            {
                this.RightDataSort();
                this.UpdateView();
                this.CreateNewNum();
                this.IsNumberBackgroundColor();
                this.SetScoreView();
            }
            else
            {
                MessageBox.Show("게임 종료");
            }
        }

        // ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ new 버튼  ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

        // newGame 버튼 클릭시 비우고 난수 발생하기
        private void button1_Click(object sender, EventArgs e)
        {
            this.GameReset();
        }

        //ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ ?? ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
        private void tableLayoutPanel1_Paint(object sender, PaintEventArgs e)
        {

        }

    }
}