자바스크립트 슬라이딩 퍼즐

Q. 자바스크립트 랜덤게임 질문이요!

1. Math.random()함수를 이용한 램던 숫자 풀 구현

2. 3×3 배열 생성하기 하고 웹페이지에 테이블 생성하기

3. 3×3 배열에 랜덤 숫자 넣어 퍼즐 테이블 완성하기

4. 키 이벤트를 활용하여 퍼즐 조작 구현하기

이 4가지 조건을 충족하는 자바코드를 만들려고 하는데요 현재 요 아래까지밖에 못했어요ㅠㅠ어떻게 해야할까요?

A. 자바스크립트로 슬라이더 퍼즐 만들기.

아래 답변은 몇 가지를 전제 합니다.

1. 위 질문에서 말하는 퍼즐을 “슬라이딩 퍼즐” 로 간주 합니다.

2. 대충의 자바스크립트 문법을 알고 있다고 가정 합니다.

3. 아래에서 소개하는 스크립트에는 jQuery를 사용했습니다.

슬라이더 퍼즐은 어릴 때 한 번쯤 해봤을만한 그… 숫자 조각을 이리 저리 밀어서 순서대로 맞추는 퍼즐입니다. 아래 사진을 보면 “아~” 할겁니다.

sliding puzzle
sliding puzzle (by eko https://www.flickr.com/photos/ekosystem/1653442249)

1. 이런 보드 게임류를 만들때는 2차원 배열을 이용합니다.

2. 2차원 배열은 그 값들에 array[y][x] 와 같이 접근할 수도 있고, array[y * X-length + x] 와 같이 1차원 적으로도 접근할 수 있습니다.

2차원 배열을 1차원 인덱스로 접근

2. 데이터와 화면표시를 분리합니다. 데이터만 조작 하는 함수를 만들고 데이터가 변경 될때마다 화면이 업데이트 되도록 합니다.

1. 화면

sliding puzzle - display

이런 모양이 되도록 할 예정입니다. 아래 테이블에는 내용이 빠져 있는데 나중에 스크립트로 채워 넣습니다.

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<title>Sliding Puzzle</title>
	<style type="text/css">
		#board {border: 1px solid #ccc;}
		#board td {border:1px solid #000; width:25px; height:25px; padding:5px; text-align: center; }
		#board td.num {background-color: yellow; }
	</style>
</head>
<body>
	<table id="board">
	</table>
</body>
</html>
2. 데이터
var YLEN = 3, // 행 길이
        XLEN = 3, // 열 길이
        blank = YLEN * XLEN - 1, // 빈칸 위치 (최초에는 맨 마지막 칸을 빈칸으로)
        BLANK = 0, // 빈칸의 값
        board = [], // 보드 배열 (YLEN x XLEN)
        boardEl = $('#board'); // 테이블 엘리먼트
3. 초기화

board 배열을 초기화 합니다. 초기화에는 2가지 방법이 있습니다.

1. 전체 배열에 무작위로 1 ~ 8 숫자를 집어 넣는다.
쉽게 구현 할 수 있고 빠르지만, 게임이 불가능한 형태로 초기화 될 수 있습니다.

2. 1 ~ 8의 숫자를 순서대로 집어 넣고 게임 규칙에 따라 무작위로 섞는다.
조금 복잡해지며 게임의 규칙을 먼저 만들고 나서 해야 하지만 게임이 불가능해지는 경우는 없습니다.

여기서는 2번째 방법을 사용하도록 하겠습니다.

function initPuzzle() { // 퍼즐 데이터를 초기화
    board = [];
    for (var y = 0; y < YLEN; y++) {
        board[y] = []; // 각 행마다 열 배열 설정
        for (var x = 0; x < XLEN; x++) {
            var idx = y * XLEN + x;
            if (idx < blank) board[y][x] = idx + 1; // 순서대로 숫자 할당
            else board[y][x] = BLANK; // 마지막 빈칸 설정
        }
    }

    // 데이터 초기화 후 화면 갱신
    updateBoard();
}

function updateBoard() { // 퍼즐 데이터를 화면에 표시
    boardEl.empty(); // 테이블을 비우고
    var html = '';
    for (var y = 0; y < YLEN; y++) {
        html += '<tr>';
        for (var x = 0; x < XLEN; x++) {
            if (board[y][x] != BLANK) html += '<td class="num">' + board[y][x] + '</td>';
            else html += '<td class="blank">&nbsp;</td>'; // 빈칸
        }
        html += '</tr>';
    }
    boardEl.html(html);
}

initPuzzle(); // 보드 데이터 초기화

일단, 이렇게 실행 하면 위의 퍼즐 그림 처럼 숫자가 순서대로 표시되고 맨 마지막 칸이 빈칸으로 설정 됩니다. 이제, 이동하는 함수를 만들고 초기화 해서 무작위로 이동을 수행 하도록 합니다.

function moveTo(to) { // 빈칸을 to 위치로 이동
    // 빈칸에 to 위치의 숫자 옮기고
    board[parseInt(blank / YLEN,10)][blank % XLEN] = board[parseInt(to / YLEN,10)][to % XLEN];
    // to 위치에 빈칸 값 설정
    board[parseInt(to / YLEN,10)][to % XLEN] = BLANK;
    // to 위치를 빈칸으로 설정
    blank = to;
    // 화면 갱신
    updateBoard();
}

function move(d, human) { // 이동 (가능한 경우)
    // d : 이동 방향 
    // human : 사람이 이동 했는지 여부 (초기화를 위해)
    switch (d) {
        case 'r': // right : 빈칸이 맨 좌측이 아니면 빈칸을 좌측으로 이동
            if (blank % XLEN > 0) moveTo(blank - 1);
            break;
        case 'l': // left : 빈칸이 맨 우측이 아니면 빈칸을 우측으로 이동
            if (blank % XLEN < XLEN - 1) moveTo(blank + 1);
            break;
        case 'd': // down : 빈칸이 멘 위가 아니면 빈칸을 위로 이동
            if (parseInt(blank / YLEN,10) > 0) moveTo(blank - XLEN);
            break;
        case 'u': // up : 빈칸이 맨 아래가 아니면 빈칸을 아래로 이동
            if (parseInt(blank / YLEN,10) < YLEN - 1) moveTo(blank + XLEN);
            break;
    }
}

move(d, human) 은 이동 방향과 사람이 이동 시켰느지 여부를 받습니다. 초기화 시에는 human 을 false 로 사람이 직접 움직일 떄는 true 로 해서 나중에 사람이 움직일 때는 별도의 액션을 취하도록 할 수 있을 겁니다. 소리를 재생 한다든지, 게임이 끝났는지 체크 한다든지 …

이동 하는 함수가 만들어 졌으니 초기화 함수를 다시 작성 합니다. 아주 여러번 무작위로 좌/우/위/아래 중에 하나를 골라 이동 시키는 겁니다.

function initPuzzle() { // 퍼즐 데이터를 초기화
    board = [];
    for (var y = 0; y < YLEN; y++) {
        board[y] = []; // 각 행마다 열 배열 설정
        for (var x = 0; x < XLEN; x++) {
            var idx = y * XLEN + x;
            if (idx < blank) board[y][x] = idx + 1; // 순서대로 숫자 할당
            else board[y][x] = BLANK; // 마지막 빈칸 설정
        }
    }
    // 이동 방향
    var moves = ['r', 'l', 'd', 'u'];
    for (var z = 0; z < 500; z++) { // 500회 동안 무작위로 이동
        move(moves[parseInt(Math.random() * 4,10)], false);
    }
    // 데이터 초기화 후 화면 갱신
    updateBoard();
}

실행 하면 아래와 같이 무작위로 이동 된 모습을 볼 수 있습니다.

초기화 후
초기화 후
4. 키보드 입력 받기

키보드 입력은 간단합니다. 눌린 키를 검사해 이동 함수를 호출 합니다.

$(document).keydown(function (e) {
    // 눌린 키에 따라 이동
    switch (e.which) {
        case 37:
            move('l', true);
            break;
        case 38:
            move('u', true);
            break;
        case 39:
            move('r', true);
            break;
        case 40:
            move('d', true);
            break;
    }
});
5. 게임 완료

사용자의 키보드 입력을 받고 이동이 일어 난 후에 모든 숫자가 순서대로 배치 되었는지 검사해 게임 완료 여부를 결정 합니다. 이동 함수에서 사람이 움직였다면 이 검사를 수행 하는 코드도 추가 합니다.

function isEnd() {
    for (var y = 0; y < YLEN; y++) {
        for (var x = 0; x < XLEN; x++) {
            var expect = y * XLEN + x + 1;  // 기대값
            if (y * XLEN + x < YLEN * XLEN - 1) { // 마지막 칸은 제외
                if (board[y][x] != expect) return; // 기대값이 아니면 중단
            }
        }
    }
    // 여기 까지 코드가 진행 됐다면. 성공.
    alert('ok');
}

function move(d, human) { // 이동 (가능한 경우)
    // 기존 코드 생략 ...
    // 사람이 움직였다면 완료 여부 체크
    if (human) isEnd();
}

다 됐습니다.

구동 화면 입니다.

참고

댓글 남기기

이 사이트는 Akismet을 사용하여 스팸을 줄입니다. 댓글 데이터가 어떻게 처리되는지 알아보세요.