가위바위보 게임을 구현하는 예제입니다.
예제는 인프런의 제로초, "조현영"님의 강의를 들으면서 공부한 내용입니다.
html 코드
<div id="computer"></div>
<div>
<button id="바위" class="btn">바위</button>
<button id="가위" class="btn">가위</button>
<button id="보" class="btn">보</button>
</div>
<div id="resultShow"></div>
css 코드
#computer {
height: 250px;
width: 140px;
}
순수 자바스크립트
1. background 이미지 설정
const computer = document.querySelector('#computer');
let left = 0; //컴퓨터 결과 = left
//0.15초마다 가위/바위/보 이미지 변경
setInterval(function() {
if (left === '0') {
left = '-100px';
} else if (left === '-100px') {
left = '-270px';
} else {
left = '0';
}
computer.style.background = 'url(imgs/rock.jpg)' + left + ' 0 no-repeat'; //0 앞에 한자리 띄우기
}, 150);
2. 버튼 클릭 이벤트 시, 나의 결과, 컴퓨터 결과 출력
document.querySelectorAll('.btn').forEach(function(el) {
el.addEventListener('click', function() {
let myChoice = this.textContent;
console.log(`나의 결과: ${myChoice} / 컴퓨터의 결과: ` ${left});
});
});
· 클릭 이벤트 설정을 위하여 버튼 3개에 className을 붙여줍니다.
유사배열
· document.querySelectorAll('.btn')은 유사배열입니다.
document.querySelectorAll('.btn')
//NodeList(3) [button#바위.btn, button#가위.btn, button#보.btn]
유사배열 이란
[]로 감싸 져 있지만 배열이 아닌 것을 유사배열이라고 합니다.
document.querySelectorAll('.btn')은 프로토타입에 forEach()를 사용할 수 있습니다.
리팩토링 no1.
left를 가위바위보로 출력을 위해 객체화(dictionary 구조)
const computer = document.querySelector('#computer');
let left = 0;
let computerPosition = {
바위: '0',
가위: '-100px',
보: '-270px',
}
let computerPosition2 = {
'0': '주먹',
'-100px': '가위',
'-270px': '보',
}
setInterval(function() {
if (left === computerPosition.바위) {
left = computerPosition.가위;
} else if (left === computerPosition.가위) {
left = computerPosition.보;
} else {
left = computerPosition.바위;
}
computer.style.background = 'url(imgs/rock.jpg)' + left + ' 0 no-repeat';
}, 150);
document.querySelectorAll('.btn').forEach(function(el) {
el.addEventListener('click', function() {
let myChoice = this.textContent;
console.log(`나의 결과: ${myChoice} / 컴퓨터의 결과: `${computerPosition2[left]});
});
});
객체는 . 또는 [] 로 호출합니다.
리팩토링 no2.
수치를 일일이 입력하는 하드코딩을 방지
const computer = document.querySelector('#computer');
let left = 0;
let computerPosition = {
바위: '0',
가위: '-100px',
보: '-270px',
}
function computerChoice(value) {
return Object.entries(computerPosition).find(function(el) {
return el[1] === value; //value = left, value값이 계속 바뀌므로 매개변수로 넣어줌
})[0]; //배열[0]
}
setInterval(function() {
if (left === computerPosition.바위) {
left = computerPosition.가위;
} else if (left === computerPosition.가위) {
left = computerPosition.보;
} else {
left = computerPosition.바위;
}
computer.style.background = 'url(imgs/rock.jpg)' + left + ' 0 no-repeat';
}, 150);
document.querySelectorAll('.btn').forEach(function(el) {
el.addEventListener('click', function() {
let myChoice = this.textContent;
console.log(`나의 결과: ${myChoice} / 컴퓨터의 결과: ` + computerChoice(left));
});
});
Object.entries() **
· Object.entries(객체): 객체를 배열로 변환합니다.
· 이차원 배열: 배열 안의 배열입니다. [[],[],[]]
console.log(Object.entries(computerPosition));
//결과: Array(3)
//0: (2) ["주먹", "0"]
//1: (2) ["가위", "-100px"]
//2: (2) ["보", "-270px"]
//length: 3
//__proto__: Array(0)
find() ***
Array.find(), 배열 안에 요소의 특정 값을 찾아주는(즉, return 이 true) 반복문입니다.
3. 승리 결과
document.querySelectorAll('.btn').forEach(function(el) {
el.addEventListener('click', function() {
let myChoice = this.textContent;
console.log(`나의 결과: ${myChoice} / 컴퓨터의 결과: ` + computerChoice(left));
//최종 결과
if (myChoice === '바위') {
if (computerChoice(left) === '가위') {
console.log('이겼습니다.');
} else if (computerChoice(left) === '바위') {
console.log('비겼습니다.');
} else {
console.log('졌습니다.');
}
} else if (myChoice === '가위') {
if (computerChoice(left) === '보') {
console.log('이겼습니다.');
} else if (computerChoice(left) === '가위') {
console.log('비겼습니다.');
} else {
console.log('졌습니다.');
}
} else if (myChoice === '보') {
if (computerChoice(left) === '바위') {
console.log('이겼습니다.');
} else if (computerChoice(left) === '보') {
console.log('비겼습니다.');
} else {
console.log('졌습니다.');
}
}
});
});
4. Timer 작동
· 버튼 클릭시 이미지 변경 stop
· 1초 후 이미지 변경 재작동
//clearInterval을 위해 변수명 지정
let timeControl = setInterval(function() {
if (left === computerPosition.바위) {
left = computerPosition.가위;
} else if (left === computerPosition.가위) {
left = computerPosition.보;
} else {
left = computerPosition.바위;
}
computer.style.background = 'url(imgs/rock.jpg)' + left + ' 0 no-repeat';
}, 150);
document.querySelectorAll('.btn').forEach(function(el) {
el.addEventListener('click', function() {
//이미지 움직임 stop
clearInterval(timeControl);
//1초 후 timeControl 재실행
setTimeout(function() {
timeControl = setInterval(function() { //timeControl 지정해야 clearInterval 계속 작동
if (left === computerPosition.바위) {
left = computerPosition.가위;
} else if (left === computerPosition.가위) {
left = computerPosition.보;
} else {
left = computerPosition.바위;
}
computer.style.background = 'url(imgs/rock.jpg)' + left + ' 0 no-repeat';
}, 150);
}, 1000)
let myChoice = this.textContent;
console.log(`나의 결과: ${myChoice} / 컴퓨터의 결과: ` + computerChoice(left));
if (myChoice === '바위') {
if (computerChoice(left) === '가위') {
console.log('이겼습니다.');
} else if (computerChoice(left) === '바위') {
console.log('비겼습니다.');
} else {
console.log('졌습니다.');
}
} else if (myChoice === '가위') {
if (computerChoice(left) === '보') {
console.log('이겼습니다.');
} else if (computerChoice(left) === '가위') {
console.log('비겼습니다.');
} else {
console.log('졌습니다.');
}
} else if (myChoice === '보') {
if (computerChoice(left) === '바위') {
console.log('이겼습니다.');
} else if (computerChoice(left) === '보') {
console.log('비겼습니다.');
} else {
console.log('졌습니다.');
}
}
});
});
리팩토링 no3.
중복되는 setInterval 함수화
let timeControl; //전역 변수 선언
function timeControlFn() {
timeControl = setInterval(function() {
if (left === computerPosition.바위) {
left = computerPosition.가위;
} else if (left === computerPosition.가위) {
left = computerPosition.보;
} else {
left = computerPosition.바위;
}
computer.style.background = 'url(imgs/rock.jpg)' + left + ' 0 no-repeat'; //0 앞에 한자리 띄우기
}, 150);
}
//함수 실행
timeControlFn();
document.querySelectorAll('.btn').forEach(function(el) {
el.addEventListener('click', function() {
clearInterval(timeControl);
setTimeout(function() {
timeControlFn();
}, 1000);
.............
});
리팩토링 no4.
최종 결과 객체화
· 객체로 바위, 가위, 보를 1, 0, -1로 각각 지정합니다.
나의 결과: 컴퓨터의 결과 | ||
이길때 | 비길때 | 질때 |
1 : 0 | 1 : -1 | 1 : -1 |
0 : -1 | 0 : 0 | 0 : 1 |
-1 : 1 | -1 : -1 | -1 : 0 |
· 규칙성:
이길 때- 나의 결과 - 컴퓨터의 결과 = 1 or -2
비길 때- 나의 결과 - 컴퓨터의 결과 = 0
· 객체의 property를 [myChoice], [computerChoice(left)]로 value값을 찾습니다.
const score = {
바위: 1,
가위: 0,
보: -1,
}
if (score[myChoice] - score[computerChoice(left)] === 0) {
console.log('비겼습니다.');
} else if (score[myChoice] - score[computerChoice(left)] === 1 ||
score[myChoice] - score[computerChoice(left)] === -2) {
console.log('이겼습니다.');
} else {
console.log('졌습니다.ㅠ');
}
리팩토링 no5.
긴 코드 간결화
· 또는 || 관계일 경우,
[Array].include() () 안의 값이 배열 안의 요소를 포함하면 true
if (score[myChoice] - score[computerChoice(left)] === 0) {
console.log('비겼습니다.');
} else if ([1, -2].includes(score[myChoice] - score[computerChoice(left)])) {
console.log('이겼습니다.');
} else {
console.log('졌습니다.ㅠ');
}
리팩토링 no6.
중복 부분 변수화
let myScore = score[myChoice];
let computerScore = score[computerChoice(left)];
let scoreDifference = myScore - computerScore;
//결과 화면 출력
resultShow = document.querySelector('#resultShow');
if (scoreDifference === 0) {
console.log('비겼습니다.');
resultShow.textContent = '비겼습니다.';
} else if ([1, -2].includes(scoreDifference)) {
console.log('이겼습니다.');
resultShow.textContent = '이겼습니다.';
} else {
console.log('졌습니다.ㅠ');
resultShow.textContent = '졌습니다.ㅠ';
}
리팩토링 no7.
버그 제거
중복 클릭할 때 clearInterval 작동 안 하고,
timeControlFn 함수가 연속적으로 작동하면서 급격히 빨라지는 현상
해결: 버튼 비활성화, 활성화 처리
let btnActive = false;
document.querySelectorAll('.btn').forEach(function(el) {
el.addEventListener('click', function() {
if (btnActive) {
return false;
}
btnActive = true;
//setInterval 멈추기
clearInterval(timeControl);
//1초 후 다시 timeControl
setTimeout(function() {
timeControlFn();
btnActive = false;
}, 1000);
let myChoice = this.textContent;
console.log(`나의 결과: ${myChoice} / 컴퓨터의 결과: ` + computerChoice(left));
let myScore = score[myChoice];
let computerScore = score[computerChoice(left)];
let scoreDifference = myScore - computerScore;
resultShow = document.querySelector('#resultShow');
if (scoreDifference === 0) {
resultShow.textContent = '비겼습니다.';
} else if ([1, -2].includes(scoreDifference)) {
resultShow.textContent = '이겼습니다.';
} else {
resultShow.textContent = '졌습니다.ㅠ';
}
});
});
스크립트 전체 코드(리팩토링 후)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>가위 바위 보 게임</title>
</head>
<style>
#computer {
height: 250px;
width: 140px;
}
</style>
<body>
<div id="computer"></div>
<div>
<button id="바위" class="btn">바위</button>
<button id="가위" class="btn">가위</button>
<button id="보" class="btn">보</button>
</div>
<div id="resultShow"></div>
<script>
const computer = document.querySelector('#computer');
let left = 0;
let computerPosition = {
바위: '0',
가위: '-100px',
보: '-270px',
}
function computerChoice(value) {
return Object.entries(computerPosition).find(function(el) {
return el[1] === value;
console.log(el[0])
})[0];
}
let timeControl;
function timeControlFn() {
timeControl = setInterval(function() {
if (left === computerPosition.바위) {
left = computerPosition.가위;
} else if (left === computerPosition.가위) {
left = computerPosition.보;
} else {
left = computerPosition.바위;
}
computer.style.background = 'url(imgs/rock.jpg)' + left + ' 0 no-repeat'; //0 앞에 한자리 띄우기
}, 150);
}
timeControlFn();
const score = {
바위: 1,
가위: 0,
보: -1,
}
let btnActive = false;
document.querySelectorAll('.btn').forEach(function(el) {
el.addEventListener('click', function() {
if (btnActive) {
return false;
}
btnActive = true;
clearInterval(timeControl);
setTimeout(function() {
timeControlFn();
btnActive = false;
}, 1000);
let myChoice = this.textContent;
console.log(`나의 결과: ${myChoice} / 컴퓨터의 결과: ` + computerChoice(left));
let myScore = score[myChoice];
let computerScore = score[computerChoice(left)];
let scoreDifference = myScore - computerScore;
resultShow = document.querySelector('#resultShow');
if (scoreDifference === 0) {
resultShow.textContent = '비겼습니다.';
} else if ([1, -2].includes(scoreDifference)) {
resultShow.textContent = '이겼습니다.';
} else {
resultShow.textContent = '졌습니다.ㅠ';
}
});
});
</script>
</body>
</html>
화면 결과(Result 클릭)
'개발 > Javascript' 카테고리의 다른 글
[js] 자바스크립트로 반응속도 테스트 구현 (0) | 2021.01.03 |
---|---|
[js] 자바스크립트로 지뢰찾기 게임 구현하기 (0) | 2021.01.02 |
[js] 자바스크립트로 로또추첨기 구현하기 (4) | 2020.12.25 |
[js] 자바스크립트로 틱택토 구현하기 (ft. e.target.value, forEach) (0) | 2020.12.22 |
[js] 자바스크립트로 숫자야구 게임 구현하기 (0) | 2020.12.18 |
댓글