반응형
물론입니다. 각 파일의 코드에 대한 상세 설명을 제공하겠습니다.
HTML (index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="viewport" content="width=device-width, initial-scale=1.0">
<title>Omok Game</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<!-- 기존 header 내용 -->
</header>
<main>
<div class="game-container">
<h1>Omok Game</h1>
<p id="turnIndicator"></p> <!-- 턴 표시 -->
<div class="board" id="board"></div>
<p id="message"></p>
<button id="resetButton">Reset Game</button>
</div>
</main>
<div id="modal" class="modal">
<div class="modal-content">
<span class="close-button" id="closeButton">×</span>
<p id="modalMessage"></p>
</div>
</div>
<footer>
<!-- 기존 footer 내용 -->
</footer>
<script src="script.js"></script>
</body>
</html>
설명
기본 HTML 구조:
<!DOCTYPE html>
: 문서가 HTML5로 작성되었음을 명시합니다.<html lang="en">
,<head>
,<meta charset="viewport" content="width=device-width, initial-scale=1.0">
: HTML 문서의 기본 설정을 정의합니다.<title>
: 페이지의 제목을 설정합니다.<link rel="stylesheet" href="styles.css">
: CSS 파일을 연결합니다.
메인 콘텐츠:
<header>
와<footer>
: 기존의 헤더와 푸터 내용을 유지합니다.<main>
: 페이지의 주요 콘텐츠를 감싸는 태그입니다.<div class="game-container">
: 게임 보드와 컨트롤 버튼을 감싸는 컨테이너입니다.<h1>Omok Game</h1>
: 게임 제목을 표시합니다.<p id="turnIndicator"></p>
: 현재 턴을 표시하는 요소입니다.<div class="board" id="board"></div>
: 오목 게임 보드를 표시하는 요소입니다.<p id="message"></p>
: 메시지를 표시하는 요소입니다.<button id="resetButton">Reset Game</button>
: 게임을 리셋하는 버튼입니다.
모달 창:
<div id="modal" class="modal">
: 모달 창의 기본 컨테이너입니다.<div class="modal-content">
: 모달 창의 콘텐츠를 감싸는 요소입니다.<span class="close-button" id="closeButton">×</span>
: 모달 창을 닫는 버튼입니다.<p id="modalMessage"></p>
: 모달 창 내에 메시지를 표시하는 요소입니다.
스크립트 파일 연결:
<script src="script.js"></script>
: JavaScript 파일을 연결합니다.
CSS (styles.css)
/* 기본 스타일 설정 */
body {
font-family: 'Arial', sans-serif;
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
background-color: #f4f4f9;
}
/* main 태그 스타일 설정 */
main {
display: flex;
justify-content: center;
align-items: center;
flex: 1;
padding: 20px;
}
/* 게임 컨테이너 스타일 설정 */
.game-container {
background: #fff;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
padding: 20px;
text-align: center;
}
/* 보드 스타일 설정 */
.board {
display: grid;
grid-template-columns: repeat(15, 30px);
grid-template-rows: repeat(15, 30px);
gap: 1px;
margin-top: 20px;
background-color: #d2b48c; /* 황토색 */
border: 2px solid #000; /* 검정색 테두리 */
}
/* 셀 스타일 설정 */
.cell {
width: 30px;
height: 30px;
background-color: #d2b48c; /* 황토색 */
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
border: 1px solid #000; /* 셀의 선을 검정색으로 설정 */
}
/* 바둑알 스타일 설정 */
.stone {
width: 80%;
height: 80%;
border-radius: 50%;
}
.black {
background-color: black;
}
.white {
background-color: white;
border: 1px solid #fff; /* 백색 돌에 흰색 테두리를 추가 */
}
/* 턴 표시 스타일 설정 */
#turnIndicator {
margin-top: 10px;
font-size: 18px;
font-weight: bold;
}
/* 버튼 스타일 설정 */
button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
margin: 5px;
border: none;
border-radius: 5px;
background-color: #6200ea;
color: white;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #3700b3;
}
/* 모달 스타일 설정 */
.modal {
display: none; /* 기본적으로 모달을 숨깁니다 */
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
}
.modal-content {
background-color: #fff;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
max-width: 400px;
border-radius: 10px;
text-align: center;
}
.close-button {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close-button:hover,
.close-button:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
설명
body 스타일:
font-family
: 기본 폰트를 'Arial'로 설정합니다.display: flex
: Flexbox 레이아웃을 사용합니다.flex-direction: column
: Flexbox 방향을 열 방향으로 설정합니다.min-height: 100vh
: 최소 높이를 뷰포트의 100%로 설정하여 전체 화면을 채우도록 합니다.margin: 0
: 기본 마진을 제거합니다.background-color: #f4f4f9
: 배경색을 연한 회색으로 설정합니다.
main 스타일:
display: flex
: Flexbox 레이아웃을 사용합니다.justify-content: center
: 가로 방향으로 중앙 정렬합니다.align-items: center
: 세로 방향으로 중앙 정렬합니다.flex: 1
: Flexbox의 남은 공간을 모두 차지하도록 설정합니다.padding: 20px
: 안쪽 여백을 20px로 설정합니다.
game-container 스타일:
background: #fff
: 배경색을 흰색으로 설정합니다.border-radius: 10px
: 모서리를 둥글게 만듭니다.box-shadow
: 그림자를 추가하여 입체감을 줍니다.padding: 20px
: 안쪽 여백을 20px로 설정합니다.text-align: center
: 텍스트를 중앙 정렬합니다.
board 스타일:
display: grid
: 그리드 레이아웃을 사용합니다.grid-template-columns: repeat(15, 30px)
: 15개의 30px 너비의 열을 만듭니다.grid-template-rows: repeat(15, 30px)
: 15개의 30px 높이의 행을 만듭니다.gap: 1px
: 셀 사이에 1px 간격을 추가합니다.margin-top: 20px
: 보드의 위쪽 여백을 20px로 설정합니다.background-color: #d2b48c
: 바둑판의 배경색을 황토색으로 설정합니다.border: 2px solid #000
: 바둑판의 테두리를 검정색으로 설정합니다.
cell 스타일:
width: 30px
: 셀의 너비를 30px로 설정합니다.height: 30px
: 셀의 높이를 30px로 설정합니다.- `background-color: #d2b48
c`: 셀의 배경색을 황토색으로 설정합니다.
display: flex
: Flexbox 레이아웃을 사용합니다.align-items: center
: 세로 방향으로 중앙 정렬합니다.justify-content: center
: 가로 방향으로 중앙 정렬합니다.cursor: pointer
: 커서를 포인터로 변경하여 클릭 가능함을 나타냅니다.border: 1px solid #000
: 셀의 선을 검정색으로 설정합니다.
stone 스타일:
width: 80%
: 바둑알의 너비를 셀의 80%로 설정합니다.height: 80%
: 바둑알의 높이를 셀의 80%로 설정합니다.border-radius: 50%
: 바둑알을 원형으로 설정합니다.
black:
background-color: black
: 검정 바둑알의 배경색을 검정색으로 설정합니다.
white:
background-color: white
: 백색 바둑알의 배경색을 흰색으로 설정합니다.border: 1px solid #fff
: 백색 바둑알의 테두리를 흰색으로 설정합니다.
turnIndicator:
margin-top: 10px
: 위쪽 여백을 10px로 설정합니다.font-size: 18px
: 폰트 크기를 18px로 설정합니다.font-weight: bold
: 폰트를 굵게 설정합니다.
button:
padding: 10px 20px
: 안쪽 여백을 10px 20px로 설정합니다.font-size: 16px
: 폰트 크기를 16px로 설정합니다.cursor: pointer
: 커서를 포인터로 변경하여 클릭 가능함을 나타냅니다.margin: 5px
: 모든 방향에 5px의 여백을 설정합니다.border: none
: 테두리를 제거합니다.border-radius: 5px
: 모서리를 둥글게 만듭니다.background-color: #6200ea
: 배경색을 보라색으로 설정합니다.color: white
: 텍스트 색상을 흰색으로 설정합니다.transition: background-color 0.3s ease
: 배경색 전환을 부드럽게 만듭니다.
button:hover:
background-color: #3700b3
: 버튼에 마우스를 올렸을 때 배경색을 더 어두운 보라색으로 변경합니다.
modal:
display: none
: 기본적으로 모달을 숨깁니다.position: fixed
: 고정 위치를 사용합니다.z-index: 1
: 다른 요소들보다 앞에 위치하도록 설정합니다.left: 0
,top: 0
,width: 100%
,height: 100%
: 모달 창이 화면 전체를 덮도록 설정합니다.overflow: auto
: 내용이 넘칠 경우 스크롤을 허용합니다.background-color: rgba(0, 0, 0, 0.5)
: 배경색을 반투명 검정색으로 설정합니다.justify-content: center
: 가로 방향으로 중앙 정렬합니다.align-items: center
: 세로 방향으로 중앙 정렬합니다.
modal-content:
background-color: #fff
: 배경색을 흰색으로 설정합니다.margin: auto
: 모달 콘텐츠를 자동으로 정렬합니다.padding: 20px
: 안쪽 여백을 20px로 설정합니다.border: 1px solid #888
: 테두리를 회색으로 설정합니다.width: 80%
: 너비를 화면의 80%로 설정합니다.max-width: 400px
: 최대 너비를 400px로 설정합니다.border-radius: 10px
: 모서리를 둥글게 만듭니다.text-align: center
: 텍스트를 중앙 정렬합니다.
close-button:
color: #aaa
: 버튼의 색상을 회색으로 설정합니다.float: right
: 버튼을 오른쪽으로 정렬합니다.font-size: 28px
: 폰트 크기를 28px로 설정합니다.font-weight: bold
: 폰트를 굵게 설정합니다.
close-button:hover, .close-button:focus:
color: black
: 마우스를 올리거나 포커스를 맞췄을 때 버튼의 색상을 검정색으로 변경합니다.text-decoration: none
: 텍스트 장식을 제거합니다.cursor: pointer
: 커서를 포인터로 변경하여 클릭 가능함을 나타냅니다.
JavaScript (script.js)
// DOM 요소를 가져옴
const boardElement = document.getElementById('board');
const turnIndicator = document.getElementById('turnIndicator');
const messageElement = document.getElementById('message');
const resetButton = document.getElementById('resetButton');
const modal = document.getElementById('modal');
const modalMessage = document.getElementById('modalMessage');
const closeButton = document.getElementById('closeButton');
// 게임 상태 변수
let board;
let currentPlayer;
const boardSize = 15;
// 이벤트 리스너 설정
resetButton.addEventListener('click', initializeGame);
closeButton.addEventListener('click', closeModal);
window.addEventListener('click', outsideClick);
// 게임 초기화 함수
function initializeGame() {
board = Array.from({ length: boardSize }, () => Array(boardSize).fill(null));
currentPlayer = 'black';
turnIndicator.textContent = `${currentPlayer.toUpperCase()}'s turn`;
messageElement.textContent = '';
renderBoard();
}
// 보드 렌더링 함수
function renderBoard() {
boardElement.innerHTML = '';
board.forEach((row, rowIndex) => {
row.forEach((cell, colIndex) => {
const cellElement = document.createElement('div');
cellElement.classList.add('cell');
cellElement.addEventListener('click', () => handleCellClick(rowIndex, colIndex));
if (cell) {
const stoneElement = document.createElement('div');
stoneElement.classList.add('stone', cell);
cellElement.appendChild(stoneElement);
}
boardElement.appendChild(cellElement);
});
});
}
// 셀 클릭 처리 함수
function handleCellClick(row, col) {
if (board[row][col] || checkWinner()) return;
board[row][col] = currentPlayer;
renderBoard();
if (checkWinner()) {
showModal(`${currentPlayer.toUpperCase()} wins!`);
messageElement.textContent = `${currentPlayer.toUpperCase()} wins!`;
} else {
currentPlayer = currentPlayer === 'black' ? 'white' : 'black';
turnIndicator.textContent = `${currentPlayer.toUpperCase()}'s turn`;
}
}
// 승리 조건 확인 함수
function checkWinner() {
// 보드 전체를 순회하며 승리 조건을 확인합니다.
for (let row = 0; row < boardSize; row++) {
for (let col = 0; col < boardSize; col++) {
const player = board[row][col];
if (player && (
checkDirection(row, col, 1, 0, player) || // 가로
checkDirection(row, col, 0, 1, player) || // 세로
checkDirection(row, col, 1, 1, player) || // 대각선 오른쪽 아래
checkDirection(row, col, 1, -1, player) // 대각선 왼쪽 아래
)) {
return true;
}
}
}
return false;
}
// 특정 방향으로 연속된 돌이 5개 있는지 확인하는 함수
function checkDirection(row, col, rowDir, colDir, player) {
let count = 0;
for (let i = 0; i < 5; i++) {
const r = row + i * rowDir;
const c = col + i * colDir;
if (r >= 0 && r < boardSize && c >= 0 && c < boardSize && board[r][c] === player) {
count++;
} else {
break;
}
}
return count === 5;
}
// 모달 창을 여는 함수
function showModal(message) {
modalMessage.textContent = message;
modal.style.display = 'flex';
}
// 모달 창을 닫는 함수
function closeModal() {
modal.style.display = 'none';
}
// 모달 창 바깥 클릭 시 닫기
function outsideClick(event) {
if (event.target == modal) {
closeModal();
}
}
// 게임 초기화 실행
initializeGame();
설명
DOM 요소를 가져옴:
boardElement
,turnIndicator
,messageElement
,
resetButton
,modal
,modalMessage
,closeButton
: HTML 요소를 가져와 변수에 저장합니다.게임 상태 변수:
board
: 바둑판 배열을 저장합니다.currentPlayer
: 현재 플레이어를 저장합니다.boardSize
: 바둑판의 크기를 설정합니다.
이벤트 리스너 설정:
resetButton.addEventListener('click', initializeGame)
: 리셋 버튼을 클릭하면 게임을 초기화합니다.closeButton.addEventListener('click', closeModal)
: 모달 창의 닫기 버튼을 클릭하면 모달 창을 닫습니다.window.addEventListener('click', outsideClick)
: 모달 창 바깥을 클릭하면 모달 창을 닫습니다.
게임 초기화 함수 (initializeGame):
board
: 바둑판을 초기화합니다.currentPlayer
: 현재 플레이어를 'black'으로 설정합니다.turnIndicator.textContent
: 현재 턴을 표시합니다.messageElement.textContent
: 메시지를 초기화합니다.renderBoard()
: 바둑판을 렌더링합니다.
보드 렌더링 함수 (renderBoard):
boardElement.innerHTML
: 바둑판을 비웁니다.board.forEach
: 바둑판 배열을 순회하며 각 셀을 생성합니다.cellElement.addEventListener('click', () => handleCellClick(rowIndex, colIndex))
: 셀을 클릭하면 handleCellClick 함수를 호출합니다.cellElement.appendChild(stoneElement)
: 셀에 돌을 추가합니다.boardElement.appendChild(cellElement)
: 바둑판에 셀을 추가합니다.
셀 클릭 처리 함수 (handleCellClick):
if (board[row][col] || checkWinner()) return
: 셀이 이미 채워져 있거나 승자가 있으면 클릭을 무시합니다.board[row][col] = currentPlayer
: 현재 플레이어의 돌을 놓습니다.renderBoard()
: 바둑판을 다시 렌더링합니다.if (checkWinner())
: 승자가 있으면 모달 창을 열고 메시지를 설정합니다.currentPlayer = currentPlayer === 'black' ? 'white' : 'black'
: 현재 플레이어를 전환합니다.turnIndicator.textContent
: 현재 턴을 표시합니다.
승리 조건 확인 함수 (checkWinner):
board.forEach
: 바둑판 전체를 순회하며 승리 조건을 확인합니다.checkDirection
: 특정 방향으로 연속된 돌이 5개 있는지 확인합니다.return true
: 승자가 있으면 true를 반환합니다.return false
: 승자가 없으면 false를 반환합니다.
특정 방향으로 연속된 돌이 5개 있는지 확인하는 함수 (checkDirection):
for (let i = 0; i < 5; i++)
: 5개의 돌이 연속으로 있는지 확인합니다.if (board[r][c] === player)
: 연속된 돌이 현재 플레이어의 돌인지 확인합니다.count++
: 연속된 돌의 개수를 증가시킵니다.return count === 5
: 연속된 돌의 개수가 5개이면 true를 반환합니다.
모달 창을 여는 함수 (showModal):
modalMessage.textContent
: 모달 창의 메시지를 설정합니다.modal.style.display = 'flex'
: 모달 창을 표시합니다.
모달 창을 닫는 함수 (closeModal):
modal.style.display = 'none'
: 모달 창을 숨깁니다.
모달 창 바깥 클릭 시 닫기 (outsideClick):
if (event.target == modal)
: 클릭한 대상이 모달 창이면closeModal()
: 모달 창을 닫습니다.
게임 초기화 실행:
initializeGame()
: 게임을 초기화합니다.
이렇게 작성된 코드를 통해 오목 게임을 구현할 수 있으며, 승리 시 모달 창을 통해 승리 메시지를 표시할 수 있습니다.
반응형
'Javascript 프로젝트 > 기능별 페이지' 카테고리의 다른 글
[기능별 페이지] lotto (0) | 2024.06.11 |
---|---|
[기능별 페이지] memory matching game2 (0) | 2024.06.10 |
[기능별 페이지] memory matching game1 (0) | 2024.06.10 |
[기능별 페이지] - number guessing game (1) | 2024.06.10 |
[기능별 페이지] 게임 - tictactoe (1) | 2024.06.10 |