프로그래밍(Web)/Javascript(TS,Node)

[바미] JS - 스도쿠 게임

Bami 2024. 10. 29. 20:11
728x90
반응형

이번에도 심심해서 만들어본 스도쿠 게임입니다!

코드

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title><!DOCTYPE html>
    <html lang="ko">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Bami`s스도쿠 게임</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100vh;
      margin: 0;
      background-color: #f0f0f0;
    }
    .sudoku-container {
      text-align: center;
    }
    .grid {
      display: grid;
      grid-template-columns: repeat(9, 40px);
      grid-template-rows: repeat(9, 40px);
      gap: 2px;
      margin: 20px 0;
    }
    .cell {
      width: 40px;
      height: 40px;
      text-align: center;
      font-size: 1.2em;
      border: 1px solid #ccc;
      background-color: #fff;
    }
    .cell:disabled {
      background-color: #ddd;
      color: #333;
    }
    /* 3x3 테두리를 굵게 설정 */
    .cell:nth-child(3n+1) {
      border-left: 2px solid #000;
    }
    .cell:nth-child(-n+9) {
      border-top: 2px solid #000;
    }
    .cell:nth-child(9n) {
      border-right: 2px solid #000;
    }
    .cell:nth-last-child(-n+9) {
      border-bottom: 2px solid #000;
    }
    .button {
      padding: 10px 20px;
      margin: 5px;
      font-size: 1em;
      cursor: pointer;
    }
  </style>
</head>
<body>

<div class="sudoku-container">
  <h1>Bami`s 스도쿠 게임</h1>
  <div class="grid" id="sudoku-grid"></div>
  <button class="button" onclick="giveHint()">힌트 보기</button>
  <button class="button" onclick="resetGame()">다시 시작</button>
</div>

<script>
  let initialBoard, board;
  let hintsLeft = 3;
  let selectedCell = null;
  let difficultyLevel = 1;

  // 스도쿠 보드 생성 함수
  function generateCompleteBoard() {
    let base = [
      [1, 2, 3, 4, 5, 6, 7, 8, 9],
      [4, 5, 6, 7, 8, 9, 1, 2, 3],
      [7, 8, 9, 1, 2, 3, 4, 5, 6],
      [2, 3, 4, 5, 6, 7, 8, 9, 1],
      [5, 6, 7, 8, 9, 1, 2, 3, 4],
      [8, 9, 1, 2, 3, 4, 5, 6, 7],
      [3, 4, 5, 6, 7, 8, 9, 1, 2],
      [6, 7, 8, 9, 1, 2, 3, 4, 5],
      [9, 1, 2, 3, 4, 5, 6, 7, 8]
    ];

    // 행, 열 및 3x3 박스를 무작위로 섞어서 스도쿠 보드를 생성합니다.
    for (let i = 0; i < 10; i++) {
      shuffleRows(base);
      shuffleColumns(base);
    }

    return base;
  }

  // 행을 무작위로 섞는 함수
  function shuffleRows(board) {
    let block = Math.floor(Math.random() * 3) * 3;
    let row1 = block + Math.floor(Math.random() * 3);
    let row2 = block + Math.floor(Math.random() * 3);
    [board[row1], board[row2]] = [board[row2], board[row1]];
  }

  // 열을 무작위로 섞는 함수
  function shuffleColumns(board) {
    let block = Math.floor(Math.random() * 3) * 3;
    let col1 = block + Math.floor(Math.random() * 3);
    let col2 = block + Math.floor(Math.random() * 3);
    for (let i = 0; i < 9; i++) {
      [board[i][col1], board[i][col2]] = [board[i][col2], board[i][col1]];
    }
  }


  function generateNewPuzzle(difficulty) {
    // 완성된 스도쿠 보드를 생성
    let completeBoard = generateCompleteBoard();

    // 초기 보드를 완성된 보드로 설정 (정답이 있는 상태)
    initialBoard = JSON.parse(JSON.stringify(completeBoard));

    // 난이도에 따라 빈 칸 개수를 설정하여 `board` 생성
    let emptyCells = 20 + difficulty * 10; // 난이도에 따라 빈 칸의 개수를 늘림
    board = JSON.parse(JSON.stringify(completeBoard));
    for (let i = 0; i < emptyCells; i++) {
      let row = Math.floor(Math.random() * 9);
      let col = Math.floor(Math.random() * 9);
      board[row][col] = null;
    }
  }


  function createGrid() {
    const grid = document.getElementById("sudoku-grid");
    grid.innerHTML = '';
    for (let row = 0; row < 9; row++) {
      for (let col = 0; col < 9; col++) {
        const cell = document.createElement("input");
        cell.type = "text";
        cell.classList.add("cell");
        cell.maxLength = 1;
        cell.dataset.row = row;
        cell.dataset.col = col;
        if (board[row][col] !== null) {
          cell.value = board[row][col];
          cell.disabled = true;
        } else {
          cell.addEventListener("click", () => selectCell(row, col));
          cell.addEventListener("input", (e) => {
            const value = parseInt(e.target.value);
            if (!value || value < 1 || value > 9) {
              e.target.value = '';
              board[row][col] = null; // 빈 셀을 null로 유지
            } else {
              board[row][col] = value; // 숫자형으로 저장

              // 퍼즐이 완성되었는지 확인
              if (isBoardFull() && checkWin()) {
                setTimeout(() => {
                  alert("퍼즐을 완성했습니다! 다음 라운드로 넘어갑니다.");
                  difficultyLevel++;
                  resetGame();
                }, 100);
              }
            }
          });
        }
        grid.appendChild(cell);
      }
    }
  }


  function checkWin() {
    for (let row = 0; row < 9; row++) {
      for (let col = 0; col < 9; col++) {
        // 각 셀이 정답과 일치하지 않으면 false 반환
        if (parseInt(board[row][col]) !== initialBoard[row][col]) {
          return false;
        }
      }
    }
    return true;
  }

  // 모든 셀이 채워졌는지 확인하는 함수
  function isBoardFull() {
    for (let row = 0; row < 9; row++) {
      for (let col = 0; col < 9; col++) {
        if (board[row][col] === null) {
          return false;
        }
      }
    }
    return true;
  }


  function selectCell(row, col) {
    selectedCell = { row, col };
  }

  function giveHint() {
    if (hintsLeft > 0 && selectedCell) {
      const { row, col } = selectedCell;
      // console.log(`Selected cell board[${row}][${col}] =`, board[row][col]); // 선택된 셀 값 상태 확인
      // console.log(`Initial board value initialBoard[${row}][${col}] =`, initialBoard[row][col]); // 초기 보드의 값 상태 확인

      // 현재 선택한 셀이 비어 있고, initialBoard에 정답 값이 있을 경우에만 힌트를 제공
      if (board[row][col] == null) {
        if (initialBoard[row][col] !== null) {
          board[row][col] = initialBoard[row][col]; // 힌트를 보드에 적용
          createGrid(); // 새로 고침하여 힌트 반영
          hintsLeft--; // 힌트 횟수 감소
          selectedCell = null; // 힌트를 준 후 선택 해제
          console.log(`Hint applied at board[${row}][${col}] =`, board[row][col]); // 힌트 적용 확인
        } else {
          alert("이 셀에는 힌트를 제공할 수 없습니다.");
        }
      } else {
        alert("이 셀에는 이미 숫자가 있습니다.");
      }
    } else if (!selectedCell) {
      alert("힌트를 받을 셀을 먼저 선택하세요.");
    } else {
      alert("힌트 사용 횟수가 초과되었습니다!");
    }
  }



  function resetGame() {
    hintsLeft = 3;
    selectedCell = null;
    generateNewPuzzle(difficultyLevel);
    createGrid();
  }
  // 초기 게임 설정
  generateNewPuzzle(difficultyLevel);
  createGrid();
</script>

</body>
</html>

 

 

728x90
반응형