- Nodejs와 함께 콘솔창에서 실행되도록 사용자 입출력 도구를 사용한다.
- 오목판 사이즈는 30x30으로 고정한 후 정사각형의 형태의 오목판을 만든다.
- 사용자 입력 도구에 좌표값 (15,15)라고 입력하여 바둑돌을 둔다.
- 흑은 1로, 백은 0으로 표기하여 화면에 흑과 백이
번갈아가면서 두도록 입력 도구가 계속 뜨도록 입력 받는다.- 오목 규칙에 따라 5줄이 먼저 완성되면 “Game over”와 같이
누가 이겼는지 승패를 알리는 출력을 만든다.- 승패가 계속 나지 않을 경우 실행 후 5분이 지나면 자동 종료시킨다.
** 제출 방법 : 작성된 js 파일과 추가된 js 파일 그리고 설치된 module을 메모장에 남겨 제출한다.
콘솔창을 통해 사용자 입력값을 받기 위해 readline
모듈을 불러왔다.
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
배열과 for문을 이용해 30x30 바둑판을 출력하였다. fill
메서드를 이용해 빈 배열로 채운 후 , map
메서드를 이용해 각 배열에 .
값을 30개씩 채워 넣어 바둑판의 좌표를 표시하였다. 그리고 for문을 이용해 바둑판을 콘솔창에 출력하였다. 개행문자가 없이 출력하기 위해 process.stdout.wirte
를 사용하였다.
const board = new Array(30).fill([]).map(() => {
const row = new Array(30).fill(" . ");
return row;
});
...
function printBoard() {
for (let i = 0; i < 30; i++) {
for (let j = 0; j < 30; j++) {
process.stdout.write(board[i][j]);
}
console.log("");
}
}
printBoard();
rl.question
을 사용해서 query
를 출력하고 값을 입력받았다. 입력된 값은 input
으로 매개변수를 가져와 split
과 map
메서드를 통해 숫자로 변환하였다. 입력받은 좌표값을 통해 바둑판에 돌을 표시하였다. 흑은 ●
백은 ○
로 표시하였으며 라운드에 따라 번갈아가게 출력되도록 하였다.
const player = [" ○ ", " ● "];
...
rl.question(
`30x30 바둑판에 [${player[round % 2]}]돌을 놓을 x, y 좌표를 띄어쓰기로 구분하여 한줄로 입력해주세요. \n`,
(input) => {
const [x, y] = input.split(" ").map((i) => Number(i) - 1);
...
board[y][x] = player[round % 2];
각 수평, 수직, 대각선 방향으로 돌을 체크하여 같은 돌이 5개가 카운트 되었을 때 승리하였다는 문자열 출력과 함께 게임이 종료된다.
function checkWin(x, y) {
const visit = [];
const count = {
horizontal: 1,
vertical: 1,
diagonalRightUp: 1,
diagonalLeftUp: 1,
};
board[y][x] = player[round % 2];
printBoard();
checkLine(x, y, "horizontal");
checkLine(x, y, "vertical");
checkLine(x, y, "diagonalRightUp");
checkLine(x, y, "diagonalLeftUp");
if (Object.values(count).find((value) => value === 5)) {
console.log(`${player[round % 2]}돌이 승리하였습니다.`);
return rl.close();
} else {
round++;
return play();
}
function checkLine(x, y, direction) {
visit.push([x, y]);
directions[direction].forEach(([i, j]) => {
const nextX = x + i;
const nextY = y + j;
if (
nextX >= 0 &&
nextX < 30 &&
nextY >= 0 &&
nextY < 30 &&
board[y][x] === board[nextY][nextX] &&
!visit.some((value) => {
return JSON.stringify(value) === JSON.stringify([nextX, nextY]);
})
) {
count[direction]++;
visit.push([nextX, nextY]);
return checkLine(nextX, nextY, direction);
}
});
}
setTimeout
을 이용해 5분이 지나면 게임이 종료되도록 하였다.
setTimeout(() => {
console.log("5분이 지나 게임을 종료합니다.");
return rl.close();
}, 5 * 60 * 1000);
const readline = require("readline");
// 콘솔로 입력값을 받기위한 모듈
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
// 게임 라운드
let round = 1;
// 30x30 바둑판
const board = new Array(30).fill([]).map(() => {
const row = new Array(30).fill(" . ");
return row;
});
// player 백돌, 흑돌
const player = [" ○ ", " ● "];
// 돌을 체크하기 위한 방향 설정
const directions = {
horizontal: [
[1, 0],
[-1, 0],
],
vertical: [
[0, 1],
[0, -1],
],
diagonalRightUp: [
[1, -1],
[-1, 1],
],
diagonalLeftUp: [
[-1, -1],
[1, 1],
],
};
// 바둑판을 콘솔에 출력
function printBoard() {
for (let i = 0; i < 30; i++) {
for (let j = 0; j < 30; j++) {
process.stdout.write(board[i][j]);
}
console.log("");
}
}
function play() {
// 5분이 지나면 게임 종료
setTimeout(() => {
console.log("5분이 지나 게임을 종료합니다.");
return rl.close();
}, 5 * 60 * 1000);
rl.question(
`30x30 바둑판에 [${
player[round % 2]
}]돌을 놓을 x, y 좌표를 띄어쓰기로 구분하여 한줄로 입력해주세요. \n`,
(input) => {
const [x, y] = input.split(" ").map((i) => Number(i) - 1);
// 숫자가 아닌 값을 받았을 경우 예외처리
if (isNaN(x) || isNaN(y)) {
console.log("좌표값은 숫자로 입력해주세요.");
return play();
}
// 좌표값을 넘는 숫자가 입력될 경우 예외처리
if (x < 0 || x > 29 || y < 0 || y > 29) {
console.log("좌표값은 1 ~ 30까지의 숫자로 입력해주세요.");
return play();
}
// 이미 돌이 놓여있는 좌표일 경우 예외처리
if (player.includes(board[y][x])) {
console.log("이미 돌이 놓여있는 좌표입니다. 다시 입력해주세요.");
return play();
}
checkWin(x, y);
}
);
function checkWin(x, y) {
const visit = [];
visit.push([x, y]);
// 방향별 돌 카운트
const count = {
horizontal: 1,
vertical: 1,
diagonalRightUp: 1,
diagonalLeftUp: 1,
};
board[y][x] = player[round % 2];
printBoard();
checkLine(x, y, "horizontal");
checkLine(x, y, "vertical");
checkLine(x, y, "diagonalRightUp");
checkLine(x, y, "diagonalLeftUp");
// 카운트 중 5가 존재한다면 게임 승리
if (Object.values(count).find((value) => value === 5)) {
console.log(`${player[round % 2]}돌이 승리하였습니다.`);
return rl.close();
} else {
round++;
return play();
}
// 방향별 돌을 체크하기 위한 함수
function checkLine(x, y, direction) {
directions[direction].forEach(([i, j]) => {
const nextX = x + i;
const nextY = y + j;
if (
nextX >= 0 &&
nextX < 30 &&
nextY >= 0 &&
nextY < 30 &&
board[y][x] === board[nextY][nextX] &&
!visit.some((value) => {
return JSON.stringify(value) === JSON.stringify([nextX, nextY]);
})
) {
count[direction]++;
visit.push([nextX, nextY]);
return checkLine(nextX, nextY, direction);
}
});
}
}
}
printBoard();
play();
https://github.com/origin1508/nipa-ict-web/blob/main/2%EC%A3%BC%EC%B0%A8/0725/omok.js
본 후기는 정보통신산업진흥원(NIPA)에서 주관하는 <AI 서비스 완성! AI+웹개발 취업캠프 - 프론트엔드&백엔드> 과정 학습/프로젝트/과제 기록으로 작성 되었습니다.