틱택토 게임

틱택토 게임 제작기 1

잡코신 2024. 4. 11. 18:00
728x90
반응형

틱택토 게임?

틱택토는 오목과 아주 유사한 형태인 추상전략 보드게임이다.

구글에 틱택토이라고 검색하면 바로 플레이 할 수도 있는 대중적이고 간단한 게임이다.

구글의 틱택토

외국어로 이 놀이를 언급한 대목에서 번역자들이 삼목이라고 번역하는 경우도 있다고 한다.

종이와 펜만 있으면 어디서든 할 수 있는 간단한 놀이이며, 심지어 종이나 펜이 없어도 모래 위에 그리거나, 돌이나 나뭇잎 같은 것들로 모양만 갖추면 언제 어디서나 할 수 있다. 판 크기는 3×3의 정사각형인 2인 전용 게임이다. 가로 세로 대각선 중 어느 한 방향으로라도 3개가 이어지면 이긴다.

 

틱택토 게임 룰

틱택토 게임을 하는 법은 엄청 간단하다.
  1. 종이 위에 가로줄과 세로줄을 각각 2개씩 긋는다.
  2. 이렇게 생긴 9칸 위에 1P는 O, 2P는 X를 번갈아가며 그린다.
  3. 먼저 O나 X를 3개가 직선으로 이어지게 만들면 승리한다.

틱택토 게임 만들기

프로그래밍 언어인 자바을 이용해서 틱택토 게임 룰에 기반한 틱택토 게임을 만든다.

public class TicTacToe {
    private int currentPlayer; // 턴을 가지고 있는 플레이어
    private boolean isGameOver = false; // 게임오버 여부
    private int[][] endStage; // 게임 종료 후 최종 상태
    private int currentTurn = 1; // 진행된 턴수
    
    public TicTacToe(int currentPlayer) {
        this.currentPlayer = currentPlayer;
    }
    
    public int getCurrentPlayer() {
        return currentPlayer;
    }

    public void setCurrentPlayer(int currentPlayer) {
        this.currentPlayer = currentPlayer;
    }
    
    public int[][] getEndStage() {
        return endStage;
    }
    
}

틱택토 클래스를 만들고 필요한 변수를 선언해준다.

생성자를 만들어 현재 플레이어를 받아오고 getter와 setter를 만들어 기본 작업을 끝내준다.

    public void resetGame(int currentPlayer) {
        this.isGameOver = false;
        this.currentPlayer = currentPlayer;
        this.endStage = null;
        this.currentTurn = 1;
    }

다음은 리셋 함수이다. 

게임의 초기상태를 저장해서 게임을 리셋하게 만들어준다.

    public void changeTurn() {
        currentPlayer = (currentPlayer == 1) ? 2 : 1;
    }

턴을 교체해주는 함수이다. 생성자로 첫 플레이어를 받아오고 이 함수로 턴을 번가라 변경해준다.

    public int inputCurrentStage(int[][] currentStage) {
        // 게임이 끝났다면 더 이상 진행하는 의미가 없으므로 판단 중단
        if(isGameOver) {
            return -99;
        }


        for(int i = 0; i < currentStage.length; i++) {
            StringBuilder rowStr = new StringBuilder();
            StringBuilder colStr = new StringBuilder();
            StringBuilder diagStr1 = new StringBuilder();
            StringBuilder diagStr2 = new StringBuilder();
            for(int j = 0; j < currentStage[i].length; j++) {
                rowStr.append(currentStage[i][j]);
                colStr.append(currentStage[j][i]);
            }
            for(int j = 0; j < currentStage.length; j++) {
                diagStr1.append(currentStage[j][j]);
                diagStr2.append(currentStage[j][2 - j]);
            }

            // 가로 판단

            if(isPlayerWin(2, rowStr.toString(), colStr.toString(), diagStr1.toString(), diagStr2.toString())) {
                isGameOver = true;
                endStage = currentStage;
                return 2;
            } else if(isPlayerWin(1, rowStr.toString(), colStr.toString(), diagStr1.toString(), diagStr2.toString())) {
                isGameOver = true;
                endStage = currentStage;
                return 1;
            } else if(currentTurn == 9) {
                return 99;
            }
        }
        currentTurn++;
        return 0;
    }
    
    private boolean isPlayerWin(int player, String rowFrag, String colFrag, String diagFrag1, String diagFrag2) {
        String p = String.valueOf(player);
        boolean result = false;
        String[] arr = {rowFrag, colFrag, diagFrag1, diagFrag2};
        for (String s : arr) {
            result = !s.contains("0") && s.equals(p + p + p);
            if (result) return result;
        }
        return result;
    }

 

  • inputCurrentStage 함수는 주어진 현재 보드 상태(currentStage)를 기반으로 게임이 진행될 때마다 호출되는 메서드다. 현재 보드를 기반으로 가로, 세로, 대각선 방향의 문자열을 구성하고, 각 방향에 대해 isPlayerWin 함수를 호출하여 승리 여부를 판단한다. 만약 어느 한 플레이어가 승리한 경우, 해당 플레이어의 번호를 반환하고 게임을 종료한다. 모든 칸이 채워진 경우(턴이 9번째까지 진행된 경우)에는 99를 반환하여 무승부임을 표시한다. 그렇지 않은 경우에는 현재 턴을 증가시키고 0을 반환하여 게임을 계속 진행한다.
  • isPlayerWin 함수는 주어진 플레이어가 현재 보드에서 이겼는지 여부를 판단하는 메서드다. 매개변수로는 해당 플레이어의 번호(player)와 각각의 가로, 세로, 대각선 방향으로 이어진 문자열(rowFrag, colFrag, diagFrag1, diagFrag2)이 주어진다.이 함수는 각 방향의 문자열에 플레이어의 번호가 연속해서 3번 등장하는지를 확인한다. 만약 연속해서 3번 등장한다면 해당 플레이어가 이겼다고 판단하고 true를 반환한다.

여기까지가 틱택토 로직 코드이다. 이제 Main으로 돌아가 플레이를 가능하게 하는 코드를 작성한다.

public class Main {
    public static void printBoard(int[][] board) {
        System.out.println("-------------");
        for (int[] row : board) {
            System.out.print("| ");
            for (int cell : row) {
                char symbol = cell == 1 ? 'X' : (cell == 2 ? 'O' : ' ');
                System.out.print(symbol + " | ");
            }
            System.out.println();
            System.out.println("-------------");
        }
    }

    public static void main(String[] args) {
    // 메인
    }
}

Main 클래스로 돌아와서 현재 보드를 출력해주는 printBoard 함수를 만들어준다.

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        TicTacToe ticTacToe = new TicTacToe(1); // 플레이어 1부터 시작

        int[][] currentStage = new int[3][3];
        int currentPlayerNum = 1;

        while (true) {
            printBoard(currentStage);

            System.out.println("Player " + currentPlayerNum + "의 차례, 놓을 곳을 선택하세요(row[1-3] column[1-3]): ");
            int row = scanner.nextInt() - 1; // 인덱스는 0부터 시작해서 1 뺌
            int col = scanner.nextInt() - 1;

            if (row < 0 || row > 2 || col < 0 || col > 2 || currentStage[row][col] != 0) {
                System.out.println("이미 놓아진 곳입니다. 다른 곳을 선택하세요.");
                continue;
            }

            currentStage[row][col] = currentPlayerNum;

            int gameResult = ticTacToe.inputCurrentStage(currentStage);
            if (gameResult == -99) {
                System.out.println("게임이 이미 종료되었습니다.");
                break;
            } else if (gameResult == 1 || gameResult == 2) {
                printBoard(currentStage);
                System.out.println("Player " + gameResult + "가 승리했습니다!");
                break;
            } else if (gameResult == 99) {
                printBoard(currentStage);
                System.out.println("비겼습니다");
                break;
            }

            ticTacToe.changeTurn();
            currentPlayerNum = ticTacToe.getCurrentPlayer();
        }

        scanner.close();
    }

main 함수에는 게임의 진행과정을 만든다.

플레이어1과 2가 번가라가면서 행과 열을 입력하면 그곳에 O와 X를 둔다.

한 턴이 지나갈 때마다  inputCurrentStage함수에게 gameResult를 받아 게임 상태를 알아낸다.

승리하면 승리한 플레이어를 알려주고 비기면 비긴다.

 

틱택토(ver.1) 플레이해보기

TicTacToe.java

package TicTacToe;

public class TicTacToe {

    private int currentPlayer;
    private boolean isGameOver = false;
    private int[][] endStage;
    private int currentTurn = 1;

    public TicTacToe(int currentPlayer) {
        this.currentPlayer = currentPlayer;
    }

    public int getCurrentPlayer() {
        return currentPlayer;
    }

    public void setCurrentPlayer(int currentPlayer) {
        this.currentPlayer = currentPlayer;
    }

    public int[][] getEndStage() {
        return endStage;
    }

    public void resetGame(int currentPlayer) {
        this.isGameOver = false;
        this.currentPlayer = currentPlayer;
        this.endStage = null;
        this.currentTurn = 1;
    }

    public void changeTurn() {
        currentPlayer = (currentPlayer == 1) ? 2 : 1;
    }

    private boolean isPlayerWin(int player, String rowFrag, String colFrag, String diagFrag1, String diagFrag2) {
        String p = String.valueOf(player);
        boolean result = false;
        String[] arr = {rowFrag, colFrag, diagFrag1, diagFrag2};
        for (String s : arr) {
            result = !s.contains("0") && s.equals(p + p + p);
            if (result) return result;
        }
        return result;
    }
    
    public int inputCurrentStage(int[][] currentStage) {
        // 게임이 끝났다면 더 이상 진행하는 의미가 없으므로 판단 중단
        if(isGameOver) {
            return -99;
        }


        for(int i = 0; i < currentStage.length; i++) {
            StringBuilder rowStr = new StringBuilder();
            StringBuilder colStr = new StringBuilder();
            StringBuilder diagStr1 = new StringBuilder();
            StringBuilder diagStr2 = new StringBuilder();
            for(int j = 0; j < currentStage[i].length; j++) {
                rowStr.append(currentStage[i][j]);
                colStr.append(currentStage[j][i]);
            }
            for(int j = 0; j < currentStage.length; j++) {
                diagStr1.append(currentStage[j][j]);
                diagStr2.append(currentStage[j][2 - j]);
            }

            // 가로 판단

            if(isPlayerWin(2, rowStr.toString(), colStr.toString(), diagStr1.toString(), diagStr2.toString())) {
                isGameOver = true;
                endStage = currentStage;
                return 2;
            } else if(isPlayerWin(1, rowStr.toString(), colStr.toString(), diagStr1.toString(), diagStr2.toString())) {
                isGameOver = true;
                endStage = currentStage;
                return 1;
            } else if(currentTurn == 9) {
                return 99;
            }
        }
        currentTurn++;
        return 0;
    }
}

Main.java

package TicTacToe;

import java.util.Scanner;

public class Main {
    public static void printBoard(int[][] board) {
        System.out.println("-------------");
        for (int[] row : board) {
            System.out.print("| ");
            for (int cell : row) {
                char symbol = cell == 1 ? 'X' : (cell == 2 ? 'O' : ' ');
                System.out.print(symbol + " | ");
            }
            System.out.println();
            System.out.println("-------------");
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        TicTacToe ticTacToe = new TicTacToe(1); // 플레이어 1부터 시작

        int[][] currentStage = new int[3][3];
        int currentPlayerNum = 1;

        while (true) {
            printBoard(currentStage);

            System.out.println("Player " + currentPlayerNum + "의 차례, 놓을 곳을 선택하세요(row[1-3] column[1-3]): ");
            int row = scanner.nextInt() - 1;
            int col = scanner.nextInt() - 1;

            if (row < 0 || row > 2 || col < 0 || col > 2 || currentStage[row][col] != 0) {
                System.out.println("이미 놓아진 곳입니다. 다른 곳을 선택하세요.");
                continue;
            }

            currentStage[row][col] = currentPlayerNum;

            int gameResult = ticTacToe.inputCurrentStage(currentStage);
            if (gameResult == -99) {
                System.out.println("게임이 이미 종료되었습니다.");
                break;
            } else if (gameResult == 1 || gameResult == 2) {
                printBoard(currentStage);
                System.out.println("Player " + gameResult + "가 승리했습니다!");
                break;
            } else if (gameResult == 99) {
                printBoard(currentStage);
                System.out.println("비겼습니다");
                break;
            }

            ticTacToe.changeTurn();
            currentPlayerNum = ticTacToe.getCurrentPlayer();
        }

        scanner.close();
    }
}

이제 실행시켜보자.

게임 플레이 화면

잘 실행되는 것을 확인 할 수 있었다.

 

Next

다음엔 불편한 프롬프트 입력이 아닌 직접 클릭이 가능하도록 하는 GUI로 발전시킬 것이다.

728x90
반응형

'틱택토 게임' 카테고리의 다른 글

틱택토 게임 제작기 2  (1) 2024.05.30