아래와 같은 모양의 오셀로 게임을 Javascript로 만들어 보자.

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>오셀로 게임</title>
<style>
body{
margin:0;
background:#222;
color:white;
font-family:Arial, sans-serif;
display:flex;
flex-direction:column;
align-items:center;
}
h1{
margin:20px 0 10px;
}
#info{
margin-bottom:10px;
font-size:20px;
}
#score{
margin-bottom:15px;
font-size:18px;
}
canvas{
background:#0f7a28;
border:6px solid #1a1a1a;
box-shadow:0 0 20px rgba(0,0,0,0.5);
cursor:pointer;
}
.buttons{
margin-top:15px;
}
button{
padding:10px 20px;
font-size:16px;
border:none;
border-radius:8px;
cursor:pointer;
}
button:hover{
opacity:0.9;
}
</style>
</head>
<body>
<h1>오셀로 (Reversi)</h1>
<div id="info">흑돌 차례</div>
<div id="score">흑 2 : 백 2</div>
<canvas id="board" width="640" height="640"></canvas>
<div class="buttons">
<button onclick="resetGame()">다시 시작</button>
</div>
<script>
const canvas = document.getElementById("board");
const ctx = canvas.getContext("2d");
const info = document.getElementById("info");
const scoreText = document.getElementById("score");
const SIZE = 8;
const CELL = 80;
let board = [];
let currentPlayer = 1; // 1 흑, 2 백
let gameOver = false;
const directions = [
[-1,-1], [0,-1], [1,-1],
[-1,0], [1,0],
[-1,1], [0,1], [1,1]
];
function initBoard(){
board = [];
for(let y=0; y<SIZE; y++){
board[y] = [];
for(let x=0; x<SIZE; x++){
board[y][x] = 0;
}
}
// 시작 돌
board[3][3] = 2;
board[4][4] = 2;
board[3][4] = 1;
board[4][3] = 1;
}
function drawBoard(){
ctx.clearRect(0,0,canvas.width,canvas.height);
// 보드
ctx.fillStyle = "#0f7a28";
ctx.fillRect(0,0,canvas.width,canvas.height);
// 격자
ctx.strokeStyle = "#000";
for(let i=0; i<=SIZE; i++){
ctx.beginPath();
ctx.moveTo(i*CELL,0);
ctx.lineTo(i*CELL,canvas.height);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0,i*CELL);
ctx.lineTo(canvas.width,i*CELL);
ctx.stroke();
}
// 돌
for(let y=0; y<SIZE; y++){
for(let x=0; x<SIZE; x++){
if(board[y][x] !== 0){
drawStone(x,y,board[y][x]);
}
}
}
// 놓을 수 있는 위치 표시
if(!gameOver){
drawHints();
}
updateScore();
}
function drawStone(x,y,player){
const cx = x * CELL + CELL/2;
const cy = y * CELL + CELL/2;
const gradient = ctx.createRadialGradient(
cx-8, cy-8, 5,
cx, cy, 30
);
if(player === 1){
gradient.addColorStop(0, "#777");
gradient.addColorStop(1, "#000");
}else{
gradient.addColorStop(0, "#fff");
gradient.addColorStop(1, "#ccc");
}
ctx.beginPath();
ctx.arc(cx, cy, 30, 0, Math.PI*2);
ctx.fillStyle = gradient;
ctx.fill();
ctx.strokeStyle = "#111";
ctx.stroke();
}
function drawHints(){
ctx.fillStyle = "rgba(255,255,0,0.35)";
for(let y=0; y<SIZE; y++){
for(let x=0; x<SIZE; x++){
if(isValidMove(x,y,currentPlayer)){
ctx.beginPath();
ctx.arc(
x*CELL + CELL/2,
y*CELL + CELL/2,
10,
0,
Math.PI*2
);
ctx.fill();
}
}
}
}
function inside(x,y){
return x>=0 && y>=0 && x<SIZE && y<SIZE;
}
function opponent(player){
return player === 1 ? 2 : 1;
}
function isValidMove(x,y,player){
if(board[y][x] !== 0) return false;
const enemy = opponent(player);
for(const [dx,dy] of directions){
let nx = x + dx;
let ny = y + dy;
let foundEnemy = false;
while(inside(nx,ny) && board[ny][nx] === enemy){
foundEnemy = true;
nx += dx;
ny += dy;
}
if(
foundEnemy &&
inside(nx,ny) &&
board[ny][nx] === player
){
return true;
}
}
return false;
}
function flipStones(x,y,player){
const enemy = opponent(player);
for(const [dx,dy] of directions){
let nx = x + dx;
let ny = y + dy;
let stones = [];
while(inside(nx,ny) && board[ny][nx] === enemy){
stones.push([nx,ny]);
nx += dx;
ny += dy;
}
if(
stones.length > 0 &&
inside(nx,ny) &&
board[ny][nx] === player
){
for(const [sx,sy] of stones){
board[sy][sx] = player;
}
}
}
}
function hasValidMove(player){
for(let y=0; y<SIZE; y++){
for(let x=0; x<SIZE; x++){
if(isValidMove(x,y,player)){
return true;
}
}
}
return false;
}
function updateScore(){
let black = 0;
let white = 0;
for(let y=0; y<SIZE; y++){
for(let x=0; x<SIZE; x++){
if(board[y][x] === 1) black++;
if(board[y][x] === 2) white++;
}
}
scoreText.textContent =
`흑 ${black} : 백 ${white}`;
}
canvas.addEventListener("click",(e)=>{
if(gameOver) return;
const rect = canvas.getBoundingClientRect();
const x = Math.floor((e.clientX - rect.left) / CELL);
const y = Math.floor((e.clientY - rect.top) / CELL);
if(!inside(x,y)) return;
if(!isValidMove(x,y,currentPlayer)) return;
board[y][x] = currentPlayer;
flipStones(x,y,currentPlayer);
currentPlayer = opponent(currentPlayer);
// 패스 처리
if(!hasValidMove(currentPlayer)){
currentPlayer = opponent(currentPlayer);
if(!hasValidMove(currentPlayer)){
gameOver = true;
finishGame();
drawBoard();
return;
}
info.textContent =
(currentPlayer === 1 ? "백" : "흑")
+ " 플레이어 패스!";
}
info.textContent =
currentPlayer === 1
? "흑돌 차례"
: "백돌 차례";
drawBoard();
});
function finishGame(){
let black = 0;
let white = 0;
for(let y=0; y<SIZE; y++){
for(let x=0; x<SIZE; x++){
if(board[y][x] === 1) black++;
if(board[y][x] === 2) white++;
}
}
if(black > white){
info.textContent = `게임 종료 - 흑 승리 (${black}:${white})`;
}
else if(white > black){
info.textContent = `게임 종료 - 백 승리 (${white}:${black})`;
}
else{
info.textContent = `무승부 (${black}:${white})`;
}
}
function resetGame(){
currentPlayer = 1;
gameOver = false;
initBoard();
info.textContent = "흑돌 차례";
drawBoard();
}
initBoard();
drawBoard();
</script>
</body>
</html>'Software > JavaScript' 카테고리의 다른 글
| Javascript 시작하기 - 국기콤보#2 (0) | 2026.10.30 |
|---|---|
| Javascript 시작하기 - 벽돌깨기 (0) | 2026.10.27 |
| Javascript 시작하기 - 1024 게임 (0) | 2026.10.26 |
| Javascript 시작하기 - 지뢰찾기 (0) | 2026.10.24 |
| Javascript 시작하기 - 장기 (0) | 2026.10.23 |
