{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "4.17.1", //express 추가.
"lodash": "4.17.20"
}
}
package.json
서버에서
npm install
명령어 입력하여 package.json의 dependencies에 입력된 tool 설치.
네이버 클라우드에서 8080port 오픈
front 쪽이랑 Backend 쪽 나눠서 디렉토리 분리
table,
th,
td {
border: 1px solid black;
}
#board > div {
height: 100px;
}
.font_4em {
font-size: 4em;
}
부트스트랩으로 안되는 부분 Class 만들어 css 관리
<!DOCTYPE html>
<html lang="ko">
<!-- 스튜디오 코드 단축키
//https://demun.github.io/vscode-tutorial/shortcuts/
//행 위아래 복사 : shift+alt+down, shift+alt+up.
//행삭제 ctrl+shift+k
// 주석 : ctrl+/
//사이드바 토글 ctrl+b
//전체화면 토글 f11
-->
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous" />
<link rel="stylesheet" href="./assets/css/main.css" />
<title>TicTacToe</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<div class="btn-group d-flex mt-4">
<button type="button" class="btn btn-primary w-100 d-flex justify-content-between">
Name1
<span id="nameO">0</span>
</button>
<button type="button" class="btn btn-danger w-100 d-flex justify-content-between">
<span id="nameX">0</span>
Name2
</button>
</div>
</div>
</div>
<div class="row py-3">
<div class="col">
<button type="button" class="btn btn-info" onclick="TicTacToe.rematch()">Rematch</button>
<button type="button" class="btn btn-info" onclick="TicTacToe.reset()">Reset</button>
</div>
<span id="message"></span>
</div>
<div class="row" id="board">
<div class="col-4 border" onclick="TicTacToe.click(0)">
<div class="text-center font_4em" id="0"></div>
</div>
<div class="col-4 border" onclick="TicTacToe.click(1)">
<div class="text-center font_4em" id="1"></div>
</div>
<div class="col-4 border" onclick="TicTacToe.click(2)">
<div class="text-center font_4em" id="2"></div>
</div>
<div class="col-4 border" onclick="TicTacToe.click(3)">
<div class="text-center font_4em" id="3"></div>
</div>
<div class="col-4 border" onclick="TicTacToe.click(4)">
<div class="text-center font_4em" id="4"></div>
</div>
<div class="col-4 border" onclick="TicTacToe.click(5)">
<div class="text-center font_4em" id="5"></div>
</div>
<div class="col-4 border" onclick="TicTacToe.click(6)">
<div class="text-center font_4em" id="6"></div>
</div>
<div class="col-4 border" onclick="TicTacToe.click(7)">
<div class="text-center font_4em" id="7"></div>
</div>
<div class="col-4 border" onclick="TicTacToe.click(8)">
<div class="text-center font_4em" id="8"></div>
</div>
</div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.20/lodash.min.js"></script>
<script src="./assets/js/main.js"></script>
</html>
html 파일
var TicTacToe = (function () {
var _init = false
var _getStatusIntervalSecond = 250
function _setMessage(message) {
document.getElementById("message").innerHTML = message
}
function _pollingGetStatus() {
$.ajax({
url: "구매한 도메인:8080(포트)/getStatus",
type: "GET",
success: function (res) {
//실시간 html 그리기.
document.getElementById("nameO").innerHTML = res.user["O"].score
document.getElementById("nameX").innerHTML = res.user["X"].score
for (var i = 0; i < res.game.block.length; i++) {
document.getElementById(i).innerHTML = res.game.block[i]
}
if (!res.game.playable) {
_setMessage("게임이 종료되었습니다.")
}
// 0.25초마다 polling 호출
setTimeout(_pollingGetStatus, _getStatusIntervalSecond)
},
})
}
function _rematch(reset) {
//새롭게 게임 시작시. 재대결 이어서 대결.
$.ajax({
url: "구매한 도메인:8080(포트)/matchStatus",
type: "GET",
data: {
reset: reset,
},
success: function (res) {
//reset 버튼 여부로 인하여 true false 처리.
if (!res.status) {
alert(res.message)
} else {
_setMessage("새 게임이 시작되었습니다.")
}
},
})
}
return {
init: function () {
if (_init) {
return false
}
_init = true
_pollingGetStatus()
},
//index : html 클릭한 파라미터
click: function (index) {
_setMessage("")
$.ajax({
//app.listen(8080)받았기 때문에 해당 메소드로 진입.
url: "구매한 도메인:8080(포트)/setMarker",
type: "GET",
data: {
index: index,
},
success: function (res) {
if (!res.status) {
alert(res.message)
}
},
})
},
rematch: function () {
_rematch()
},
reset: function () {
_rematch(true)
},
}
})()
TicTacToe.init()
main.js
프론트 부분은 html 받아온 값만 이벤트 처리를 back단으로 넘기는 형식으로 구현하였다.
var express = require("express")
var app = express()
var _ = require("lodash")
// CORS대응 코드.
app.all("/*", function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*")
res.header("Access-Control-Allow-Headers", "X-Requested-With")
next()
})
// DATABASE
var _database = {
game: {
playable: true,
count: 0,
block: ["", "", "", "", "", "", "", "", ""],
winner: "", // [X, O, _, ]
},
user: {
X: { name: "user1", score: 0 },
O: { name: "user2", score: 0 },
},
}
var _successCondition = [
//틱택토 게임 성공의 경우의 수.
["0", "1", "2"],
["3", "4", "5"],
["6", "7", "8"],
["0", "3", "6"],
["1", "4", "7"],
["2", "5", "8"],
["0", "4", "8"],
["2", "4", "6"],
]
function _getMarker() {
//처음 시작시 X,O 표시
return _database.game.count == 0 || _database.game.count % 2 == 0 ? "X" : "O"
}
function _getResult(marker) {
var markeredIndex = _.compact(
_.map(_database.game.block, function (value, index) {
return value == marker ? index.toString() : ""
})
)
var checkNumber = Math.abs(3 - markeredIndex.length)
_.map(_successCondition, function (condition) {
if (_.xor(condition, markeredIndex).length == checkNumber) {
_database.user[marker].score++
_database.game.playable = false
_database.game.winner = marker
}
})
if (_database.game.playable && _database.game.count == 9) {
_database.game.winner = "_"
_database.game.playable = false
}
}
//matchStatus
app.get("/matchStatus", function (req, res) {
var response = {
status: false,
message: "Wrong Access.",
}
if (_database.game.playable) {
response.message = "게임이 진행중입니다."
} else {
_database = {
game: {
playable: true,
count: 0,
block: ["", "", "", "", "", "", "", "", ""],
winner: "", // [X, O, _, ]
},
user: {
X: { name: "baek", score: _database.user["X"].score },
O: { name: "oh", score: _database.user["O"].score },
},
}
if (req.query.reset) {
_database.user = {
X: { name: "baek", score: 0 },
O: { name: "oh", score: 0 },
}
}
response = {
status: true,
message: "게임이 초기화되었습니다.",
}
}
res.send(response)
})
// getStatus
app.get("/getStatus", function (req, res) {
res.send(_database)
})
/*
- 마커를 입력한다.
{
index: int(required)
}
*/
app.get("/setMarker", function (req, res) {
var response = {
status: false,
message: "Wrong Access.",
}
//잘못된 값이 들어올경우의 예외처리
if (typeof req.query.index === "undefined") {
response.message += "(-1)"
} else if ([0, 1, 2, 3, 4, 5, 6, 7, 8].includes(req.query.index)) {
response.message += "(-2)"
} else if (!_database.game.playable) {
response.message = "게임이 종료되었습니다."
} else if (_database.game.block[req.query.index].length) {
response.message = "이미 선택된 블록입니다."
} else {
//해당 예외처리가 아니면 O,X 찍어주고 선택횟수가 5이상 넘넘어가면 게임종료.
_database.game.block[req.query.index] = _getMarker()
_database.game.count++
if (_database.game.count >= 5) {
_getResult(_database.game.block[req.query.index])
}
response = {
status: true,
message: "Success.",
}
}
res.send(response)
})
//(오픈된 방화벽 port)
app.listen(8080)
중요 로직 및 통신관련부분은 index.js로 구분하여 처리
해당 소스 부분 수정시에는
node index.js
를 서버에서 입력하여 실행
다른 브라우저.(즉 다른 세션)에서 동기화 되는것 테스트.
'dev' 카테고리의 다른 글
비쥬얼스튜디오 코드 설정 동기화 (0) | 2020.09.24 |
---|---|
[Dev스터디 5일차] 틱택톡 만들어보기 (개선1) (0) | 2020.09.18 |
[Dev스터디 4일차] 틱택톡 만들어보기 (소스 분리) (0) | 2020.09.14 |
[dev 스터디 3일차] 틱택톡 만들어보기 (jquery 사용) (0) | 2020.09.11 |
[dev 스터디 2일차] 틱택톡 만들어보기 (jquery 사용) (0) | 2020.09.10 |