발전하는 춘배

[원고, SDL3] 2. 윈도우 오목게임 만들기 기록 1 본문

.원고

[원고, SDL3] 2. 윈도우 오목게임 만들기 기록 1

춘배0 2025. 8. 24. 12:59

요새 오목 재밌게 해서 오목만들기로했음.

SDL로 GUI 구현해보는게 목표라서

게임 로직 자체는 간단해야 흥미 안 떨어지고 완성할 듯 싶기도 해서 오목으로 정함.

 

일단 기본로직완성함.

 

class User
{
private:
public:
    unsigned int totalGameCount;
    unsigned int winGameCount;
    string nickname;
    User(string nickname);
    void AddWinGameCount();
    ~User();
};
User::User(string _nickname)
{
    nickname = _nickname;
    totalGameCount = winGameCount = 0;
}
void User::AddWinGameCount() {
    winGameCount++;
}
User::~User()
{
}

 

class GameOver
{
private:
    User* winner = nullptr;
    User* loser = nullptr;
public:
    bool isGameOver = false;
    GameOver(/* args */);
    void SetResult(User _winner, User _loser);
    User GetWinner();
    ~GameOver();
};
GameOver::GameOver(/* args */)
{
}
void GameOver::SetResult(User _winner, User _loser) {
    winner = &_winner;
    loser = &_loser;
}
User GameOver::GetWinner() {
    return *winner;
}
GameOver::~GameOver()
{
}

 

class Game
{
private:
    User user1;
    User user2;
    array<array<int,BOARDSIZE>, BOARDSIZE> board;
    GameOver* gameOver;

    bool isUser1Turn;
public:
    Game(User user1, User user2);
    void StartGame();
    bool CheckGameOver(int usernum);
    void DisplayBoard();
    ~Game();
};
Game::Game(User user1, User user2) : user1(user1), user2(user2)
{
    board = InitializeBoard();
    gameOver = new GameOver();
    isUser1Turn = true;
    StartGame();
}
Game::~Game()
{
    delete gameOver;
}
void Game::StartGame() {
    cout << "게임 시작!" << endl;
    user1.totalGameCount++;
    user2.totalGameCount++;

    DisplayBoard();

    while (!this->gameOver->isGameOver)
    {
        // 착수
        int x, y;
        cin >> x >> y;
        while(x >= BOARDSIZE || y >= BOARDSIZE || board[x][y] != 0) {
            cout << "잘못된 좌표" << endl;
            cin >> x >> y;
        }
        if(isUser1Turn) {
            board[x][y] = 1;
        } else {
            board[x][y] = 2;
        }

        DisplayBoard();

        // 5목 확인
        if(CheckGameOver(isUser1Turn ? 1 : 2)) {
            break;
        }

        // 턴종료
        isUser1Turn = !isUser1Turn;
    }

    // 게임종료
    User winner = this->gameOver->GetWinner();
    cout << "승자: " << winner.nickname << endl;
    winner.AddWinGameCount();
}
void Game::DisplayBoard() {
    for (size_t i = 0; i < BOARDSIZE; i++)
    {
        for (size_t j = 0; j < BOARDSIZE; j++)
        {
            if(board[i][j] == 0) {
                if(i == 0) {
                    if(j == 0) {
                        cout << "┌─";
                    }
                    else if(j == BOARDSIZE - 1) {
                        cout << "─┐";
                    }
                    else {
                        cout << "─┬─";
                    }
                }
                else if(i == BOARDSIZE - 1) {
                    if(j == 0) {
                        cout << "└─";
                    }
                    else if(j == BOARDSIZE - 1) {
                        cout << "─┘";
                    }
                    else {
                        cout << "─┴─";
                    }
                } else {
                    if (j == 0) {
                        cout << "├─";
                    }
                    else if (j == BOARDSIZE - 1) {
                        cout << "─┤";
                    }
                    else {
                        cout << "─┼─";
                    }
                }
            } else {
                if(board[i][j] == 1) {
                    if(j == 0) {
                        cout << "○─";
                    }
                    else if (j == BOARDSIZE - 1)
                        cout << "─○";
                    else
                        cout << "─○─";
                } else {
                    if(j == 0) {
                        cout << "●─";
                    }
                    else if (j == BOARDSIZE - 1)
                        cout << "─●";
                    else
                        cout << "─●─";
                }
            }
        }
        cout << endl;
        
    }
    
}
bool Game::CheckGameOver(int usernum) {
    // TODO: 알고리즘 개선
    int cnt = 0;

    // 1. 세로췍
    for (size_t i = 0; i < BOARDSIZE; i++)
    {
        for (size_t j = 0; j < BOARDSIZE; j++)
        {
            if (board[i][j] == usernum)
            {
                cnt = 1;
                for (size_t k = 1; k < 5; k++)
                {
                    if(i+k < BOARDSIZE && board[i+k][j] == usernum) {
                        cnt++;
                        if (cnt == 5) {
                            // 5목완성
                            this->gameOver->isGameOver = true;
                            this->gameOver->SetResult(usernum == 1 ? user1 : user2, usernum == 1 ? user2 : user1);
                            return true;
                        }
                    } else {
                        cnt = 0;
                        break;
                    }
                }
                
            }
        }        
    }

    // 2. 가로췍
    for (size_t i = 0; i < BOARDSIZE; i++)
    {
        for (size_t j = 0; j < BOARDSIZE; j++)
        {
            if (board[i][j] == usernum)
            {
                cnt = 1;
                for (size_t k = 1; k < 5; k++)
                {
                    if(j+k < BOARDSIZE && board[i][j+k] == usernum) {
                        cnt++;
                        if (cnt == 5) {
                            // 5목완성
                            this->gameOver->isGameOver = true;
                            this->gameOver->SetResult(usernum == 1 ? user1 : user2, usernum == 1 ? user2 : user1);
                            return true;
                        }
                    } else {
                        cnt = 0;
                        break;
                    }
                }
                
            }
        }        
    }

    // 3. 우하향대각선췍
    for (size_t i = 0; i < BOARDSIZE; i++)
    {
        for (size_t j = 0; j < BOARDSIZE; j++)
        {
            if (board[i][j] == usernum)
            {
                cnt = 1;
                for (size_t k = 1; k < 5; k++)
                {
                    if(i+k < BOARDSIZE && j+k < BOARDSIZE && board[i+k][j+k] == usernum) {
                        cnt++;
                        if (cnt == 5) {
                            // 5목완성
                            this->gameOver->isGameOver = true;
                            this->gameOver->SetResult(usernum == 1 ? user1 : user2, usernum == 1 ? user2 : user1);
                            return true;
                        }
                    } else {
                        cnt = 0;
                        break;
                    }
                }
                
            }
        }        
    }
    // 4. 좌하향대각선췍
    for (size_t i = 0; i < BOARDSIZE; i++)
    {
        for (size_t j = 0; j < BOARDSIZE; j++)
        {
            if (board[i][j] == usernum)
            {
                cnt = 1;
                for (size_t k = 1; k < 5; k++)
                {
                    if(i+k < BOARDSIZE && j-k >= 0 && board[i+k][j-k] == usernum) {
                        cnt++;
                        if (cnt == 5) {
                            // 5목완성
                            this->gameOver->isGameOver = true;
                            this->gameOver->SetResult(usernum == 1 ? user1 : user2, usernum == 1 ? user2 : user1);
                            return true;
                        }
                    } else {
                        cnt = 0;
                        break;
                    }
                }
                
            }
        }        
    }
    return false;
}

요기 췍게임오버는 진짜 대충 짰음.

알고리즘에 자신이 없어서 그냥 시간 좀 걸리더라도 오류없는 확실한 방법으로..

 

int main(void) {

    // 임시유저
    User user1(string("user1"));
    User user2(string("user2"));
    

    // 게임 생성
    Game game(user1, user2);
    

    return 0;
}

 

오목 기본로직완성.

렌주룰 적용은 아직 때가 아님

이제 SDL을 써먹어 보자.

 

반응형