본문 바로가기
개발노트/오목게임_C#

C# 오목 게임 개발 #5

by Jaayou 2023. 1. 30.
반응형

이번 회차에서는 오목게임의 근간이 되는 오목클래스를 디자인하고 우선 오목판을 그려봅니다.

오목클래스는 개발이 완료될 때까지 단계적으로 구현해야 할 중요한 영역입니다. 객체지향의 핵심이 되는 클래스/객체 개념은 별도로 꼭 학습해 보시길 권장합니다.

 

오목클래스(COmok) 정의

오목클래스는 오목게임의 중요한 로직을 담고 있는 핵심클래스가 됩니다. 단계적으로 진행하면서 계속 개발하고 보완해 나갈 예정입니다. 오목클래스는 COmok.cs라는 별도의 파일에 작성합니다.

namespace Omok
{
    internal class COmok
    {
    	...
    }
}

 

멤버변수

오목의 여러 속성들을 멤버변수로 정의합니다.

  • 주요 상수 정의
  • 게임환경변수 정의
  • 오목판정보 배열 정의
Graphics g;

int boardMargin = 60;
int boardSize = 19;
int boardInterval = 50;
int stoneSize = 48;
int dotSize = 8;
bool gameOver = false;
char playerType = 'C';
char firstPlayer = 'H';

//착수정보List
List<CPoint> mainList = new List<CPoint>();

//오목판 배열(15*15 or 19*19)
char[,] mainBoard;

readonly string[][] omokPattern = new string[2][]
{
    new string[] { "EBBBBBE", "EBBBBBW", "EBBBBBX", "WBBBBBE", "WBBBBBW", "WBBBBBX", "XBBBBBE", "XBBBBBW", "XBBBBBX" },
    new string[] { "WWWWW" }
};

 

생성자

생성자는 객체가 생성될 때 최초에 한번 실행되는 함수로써 주로 초기화를 진행합니다.

  • 그래픽 객체 생성
  • 오목판 사이즈 초기화
  • 상대선수 초기화
  • 흑 선수 초기화
  • 사이즈에 따른 오목판 격자간격 값 초기화
  • 오목판 배열정보 생성
public COmok(Graphics graphics, int boardSize, char playerType, char firstPlayer)
{
    this.g = graphics;
    this.boardSize = boardSize;
    this.playerType = playerType;
    this.firstPlayer = firstPlayer;

    mainBoard = new char[this.boardSize + 1, this.boardSize + 1];

    this.boardInterval = boardSize == 15 ? 50 : 39;
    this.stoneSize = boardSize == 15 ? 48 : 37;
}

 

멤버함수(메서드)

처리에 필요한 함수들을 정의합니다. 오목객체가 생성되면 멤버함수들을 이용해서 오목과 관련된 대부분의 처리를 수행하게 됩니다.

  • 오목판 그리기 : 오목판 영역을 초기화하고 격자와 점을 그리는 함수입니다.
public void DrawBoard(Graphics g)
{
    Pen pen = new Pen(Color.Black);
    Point point;
    char[] alphabet = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S' };

    //오목판 격자 표시
    for (int i = 0; i < boardSize - 1; i++)
    {
        for (int j = 0; j < boardSize - 1; j++)
        {
            Rectangle rec = new Rectangle((i * boardInterval) + boardMargin, (j * boardInterval) + boardMargin, boardInterval, boardInterval);
            g.DrawRectangle(pen, rec);
        }
    }

    //점 표시
    if (boardSize == 15)
    {
        DrawStone(g, 4, 4, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 12, 4, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 4, 12, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 8, 8, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 12, 12, 'B', 0, false, (int)DrawType.BoardPoint);
    }
    else if (boardSize == 19)
    {
        DrawStone(g, 4, 4, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 10, 4, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 16, 4, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 4, 10, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 10, 10, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 16, 10, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 4, 16, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 10, 16, 'B', 0, false, (int)DrawType.BoardPoint);
        DrawStone(g, 16, 16, 'B', 0, false, (int)DrawType.BoardPoint);
    }

    //위치번호, 알파벳 표시
    for (int i = 1; i <= boardSize; i++)
    {
        g.DrawString(i.ToString(), new Font("Arial", 10), new SolidBrush(Color.Black), 35, (boardInterval * i) + (boardSize == 15 ? 3 : 14));
        g.DrawString(alphabet[i - 1].ToString(), new Font("Arial", 10), new SolidBrush(Color.Black), (boardInterval * i) + (boardSize == 15 ? 5 : 15), 30);
    }
}

 

  • 오목판 점 그리기 : 오목판의 주어진 위치에 점을 그려주는 함수입니다.
private void DrawStone(Graphics g, int x, int y)
{
	Point point = GetScreenPosition(new Point(x, y));

	point.X = (x - 1) * boardInterval + boardMargin - (dotSize / 2);
	point.Y = (y - 1) * boardInterval + boardMargin - (dotSize / 2);
	g.FillEllipse(Brushes.Black, new Rectangle(point, new Size(dotSize, dotSize)));
	g.DrawEllipse(Pens.Black, new Rectangle(point, new Size(dotSize, dotSize)));
}

//오목판 위치정보를 화면 위치정보로 변경
private Point GetScreenPosition(Point point)
{
	return new Point((point.X - 1) * boardInterval + boardMargin - (stoneSize / 2), (point.Y - 1) * boardInterval + boardMargin - (stoneSize / 2));
}

 

오목클래스(COmok.cs) 전체 코드

현재까지 정의한 오목클래스 전체 소스코드입니다. 오목클래스는 별도의 COmok.cs파일로 생성합니다.

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

namespace Omok
{
    internal class COmok
    {
        Graphics g;

        int boardMargin = 60;
        int boardSize = 19;
        int boardInterval = 50;
        int stoneSize = 48;
        int dotSize = 8;
        bool gameOver = false;
        char playerType = 'C';
        char firstPlayer = 'H';

        //착수정보List
        List<CPoint> mainList = new List<CPoint>();

        //오목판 배열(15*15 or 19*19)
        char[,] mainBoard;

        readonly string[][] omokPattern = new string[2][]
        {
            new string[] { "EBBBBBE", "EBBBBBW", "EBBBBBX", "WBBBBBE", "WBBBBBW", "WBBBBBX", "XBBBBBE", "XBBBBBW", "XBBBBBX" },
            new string[] { "WWWWW" }
        };

        public COmok(Graphics graphics, int boardSize, char playerType, char firstPlayer)
        {
            this.g = graphics;
            this.boardSize = boardSize;
            this.playerType = playerType;
            this.firstPlayer = firstPlayer;

            mainBoard = new char[this.boardSize + 1, this.boardSize + 1];

            this.boardInterval = boardSize == 15 ? 50 : 39;
            this.stoneSize = boardSize == 15 ? 48 : 37;
        }

        public void DrawBoard(Graphics g)
        {
            Pen pen = new Pen(Color.Black);
            Point point;
            char[] alphabet = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S' };

            //오목판 격자 표시
            for (int i = 0; i < boardSize - 1; i++)
            {
                for (int j = 0; j < boardSize - 1; j++)
                {
                    Rectangle rec = new Rectangle((i * boardInterval) + boardMargin, (j * boardInterval) + boardMargin, boardInterval, boardInterval);
                    g.DrawRectangle(pen, rec);
                }
            }

            //점 표시
            if (boardSize == 15)
            {
                DrawStone(g, 4, 4, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 12, 4, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 4, 12, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 8, 8, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 12, 12, 'B', 0, false, (int)DrawType.BoardPoint);
            }
            else if (boardSize == 19)
            {
                DrawStone(g, 4, 4, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 10, 4, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 16, 4, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 4, 10, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 10, 10, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 16, 10, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 4, 16, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 10, 16, 'B', 0, false, (int)DrawType.BoardPoint);
                DrawStone(g, 16, 16, 'B', 0, false, (int)DrawType.BoardPoint);
            }

            //위치번호, 알파벳 표시
            for (int i = 1; i <= boardSize; i++)
            {
                g.DrawString(i.ToString(), new Font("Arial", 10), new SolidBrush(Color.Black), 35, (boardInterval * i) + (boardSize == 15 ? 3 : 14));
                g.DrawString(alphabet[i - 1].ToString(), new Font("Arial", 10), new SolidBrush(Color.Black), (boardInterval * i) + (boardSize == 15 ? 5 : 15), 30);
            }
        }

        private void DrawStone(Graphics g, int x, int y)
        {
            point.X = (x - 1) * boardInterval + boardMargin - (dotSize / 2);
            point.Y = (y - 1) * boardInterval + boardMargin - (dotSize / 2);
            g.FillEllipse(Brushes.Black, new Rectangle(point, new Size(dotSize, dotSize)));
            g.DrawEllipse(Pens.Black, new Rectangle(point, new Size(dotSize, dotSize)));
        }

        private Point GetScreenPosition(Point point)
        {
            return new Point((point.X - 1) * boardInterval + boardMargin - (stoneSize / 2), (point.Y - 1) * boardInterval + boardMargin - (stoneSize / 2));
        }
    }
}

 

반응형

오목판 그리기

현재까지 정의한 오목클래스와 오목판 그리기 멤버함수를 이용해서 오목판을 그리는 코드를 작성합니다.

 

메인 프로그램 수정

  • Form1.cs 파일에 오목객체 생성하는 코드와 오목판 그리는 코드를 추가합니다.
  • 오목객체 생성 : omok = new COmok(g, boardSize, playType, firstPlayer);
  • 오목판 그리는 멤버함수 호출 : omok.DrawBoard(e.Graphics);

Form1 로드 시에 오목객체를 생성하고 Refresh() 이벤트가 발생할 때마다 오목판이 다시 그려지도록 panel_Paint() 함수에 추가해 준다.

private void Form1_Load(object sender, EventArgs e)
{
    g = CreateGraphics();

    //게임설정 초기화
    radioButtonSize15.Checked = true;
    radioButtonEnemyCom.Checked = true;
    radioButtonFirstHuman.Checked = true;

    if (radioButtonSize15.Checked) boardSize = 15;
    if (radioButtonSize19.Checked) boardSize = 19;
    if (radioButtonEnemyHuman.Checked) playType = 'H';
    if (radioButtonEnemyCom.Checked) playType = 'C';
    if (radioButtonFirstHuman.Checked) firstPlayer = 'H';
    if (radioButtonFirstCom.Checked) firstPlayer = 'C';

    //COmok 객체 생성
    omok = new COmok(g, boardSize, playType, firstPlayer);
}
        
private void panel_Paint(object sender, PaintEventArgs e)
{
    omok.DrawBoard(e.Graphics);
}

 

실행결과 화면

지금까지의 코드를 실행하면 아래와 같이 오목판이 그려지게 됩니다.

현재는 15*15 사이즈로 설정되었기 때문에 아래와 같은 형태로 그려집니다.

앞으로 이 오목판 위에 착수시마다 오목돌을 그려나가게 됩니다.

반응형

'개발노트 > 오목게임_C#' 카테고리의 다른 글

C# 오목 게임 개발 #7  (0) 2023.01.30
C# 오목 게임 개발 #6  (0) 2023.01.30
C# 오목 게임 개발 #4  (0) 2023.01.30
C# 오목 게임 개발 #3  (0) 2023.01.30
C# 오목 게임 개발 #2  (0) 2023.01.30

댓글