c++로 짰던걸 자바스크립트로 수작업으로 변환함




"use strict"; // macros const KC_LEFT = 37; const KC_RIGHT = 39; const KC_UP = 38; const KC_DOWN = 40; const IMAGE_PATHS = [ "narrow_stair.png", "night_street.png", "snow_kid.png", "pretty_bird.png", "tajmahal.png", ]; // constants const STACK_ROWS = 18; const STACK_COLUMNS = 10; const STACK_DIMENSION = (STACK_ROWS) * (STACK_COLUMNS); const PIECE_ROWS = 5; const PIECE_COLUMNS = 5; const PIECE_DIMENSION = (PIECE_ROWS) * (PIECE_COLUMNS); const BLOCK_PIXEL = 30; const CANVAS_WIDTH = (STACK_COLUMNS) * (BLOCK_PIXEL); const CANVAS_HEIGHT = (STACK_ROWS) * (BLOCK_PIXEL); const FALLDOWN_INTERVAL = 200; const SAMPLE_SIZE = 4; const SAMPLES = [ [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 ], [ 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 ] ]; // board elements var stack = []; var piece = []; var pos_piece = { x:0, y:0 }; var score; // variables var canvas; var ctx; var img_background; var timer_falldown; // procedure functions function onKeydown(event) {} function onClick(event) {} function onPaint() {} function loadNewImage() {} // board functions function initializeBoard() {} function updateBoard() {} function isPieceLanded() {} function mergePieceIntoStack() {} function updateStack() {} function isStackFull() {} function isRowEmpty(row) {} function clearRow(row) {} function resetPiece(type) {} function movePiece(offset_x, offset_y) {} function rotatePiece(is_clockwise) {} function isValidPiece(test, pos_x, pos_y) {} function colBlockInStack(idx) { return (idx % STACK_COLUMNS); } function rowBlockInStack(idx) { return Math.floor(idx / STACK_COLUMNS); } function colBlockInPiece(idx) { return (pos_piece.x + (idx % 5)); } function rowBlockInPiece(idx) { return (pos_piece.y + Math.floor(idx / 5)); } function posToIndexInStack(col, row) { return ((STACK_COLUMNS * row) + col); } $(function() { // Get the canvas element. canvas = $('#canvas').get(0); if (canvas == null || canvas.getContext == null) { alert("캔버스를 사용할 수 없습니다."); return; } // Resize the canvas. canvas.width = CANVAS_WIDTH; canvas.height = CANVAS_HEIGHT; // Get the 2d context. ctx = canvas.getContext('2d'); if (ctx == null) { alert("캔버스 컨텍스트를 사용할 수 없습니다."); return; } // Register event handlers. $(document).keydown(onKeydown); $(document).click(onClick); // Start the game. initializeBoard(); loadNewImage(); timer_falldown = setInterval(onTimer,FALLDOWN_INTERVAL); }); function onTimer() { // When the game is going on... if (isStackFull() == false) { // Get the piece to fall down according to the timer. movePiece(0, -1); // Update the board. updateBoard(); // Paint the changed board. onPaint(); // If the stack is full, finish the game. if (isStackFull() == true) { clearInterval(timer_falldown); timer_falldown = null; // Change the opacity of the canvas. $(canvas).addClass('failed'); // Process and display records after a while. setTimeout(function() { // Update records in a database var userId = document.getElementById('user-id').value; location.replace('update_record.php?&score=' + score); }, 1000); } } } function onKeydown(event) { var is_changed; // When the game is going on... if (isStackFull() == false && timer_falldown != null) { // Move or rotate the piece according to the user input. // The piece may not be changed if an overlapping occurs. switch (event.keyCode) { case KC_RIGHT: is_changed = movePiece(1, 0); break; case KC_LEFT: is_changed = movePiece(-1, 0); break; case KC_DOWN: is_changed = movePiece(0, -1); break; case KC_UP: is_changed = rotatePiece(true); break; default: is_changed = false; break; } // Check if the piece has changed its position. if (is_changed == true) { // If so, update the board. updateBoard(); // Paint the changed board. onPaint(); // If the stack is full, finish the game. if (isStackFull() == true) { clearInterval(timer_falldown); timer_falldown = null; // Change the opacity of the canvas. $(canvas).addClass('failed'); // Process and display records after a while. setTimeout(function() { // Update records in a database var userId = document.getElementById('user-id').value; location.replace('update_record.php?&score=' + score); }, 1000); } } } } function onClick(event) { // When the game is going on... if (isStackFull() != true) { // Pause or resume the game. if (timer_falldown != null) { clearInterval(timer_falldown); timer_falldown = null; } else { timer_falldown = setInterval(onTimer, FALLDOWN_INTERVAL); } // Change the opacity of the canvas. $(canvas).toggleClass('paused'); } } function onPaint() { ctx.fillStyle = '#244233'; ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); // # Paint background images ctx.drawImage(img_background, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); // # Paint every block in the stack. for (var i = 0; i < STACK_DIMENSION; i++) { if (stack[i] == false) continue; ctx.strokeStyle = '#00f'; ctx.fillStyle = '#ff0'; ctx.shadowBlur = 5; ctx.fillRect( colBlockInStack(i) * BLOCK_PIXEL, CANVAS_HEIGHT - (rowBlockInStack(i) + 1) * BLOCK_PIXEL, BLOCK_PIXEL, BLOCK_PIXEL); ctx.strokeRect( colBlockInStack(i) * BLOCK_PIXEL, CANVAS_HEIGHT - (rowBlockInStack(i) + 1) * BLOCK_PIXEL, BLOCK_PIXEL, BLOCK_PIXEL); } // # Paint every block in the piece. for (var i = 0; i < PIECE_DIMENSION; i++) { if (piece[i] == false) continue; ctx.strokeStyle = '#00f'; ctx.fillStyle = '#ff0'; ctx.shadowBlur = 5; ctx.fillRect( colBlockInPiece(i) * BLOCK_PIXEL, CANVAS_HEIGHT - (rowBlockInPiece(i) + 1) * BLOCK_PIXEL, BLOCK_PIXEL, BLOCK_PIXEL); ctx.strokeRect( colBlockInPiece(i) * BLOCK_PIXEL, CANVAS_HEIGHT - (rowBlockInPiece(i) + 1) * BLOCK_PIXEL, BLOCK_PIXEL, BLOCK_PIXEL); } // # Display score at the right-top of the screen. ctx.font = "bold 30px cambria"; ctx.fillStyle = '#fff'; ctx.textAlign = "center"; ctx.textBaseline = "top"; ctx.shadowColor = "#000"; ctx.shadowOffsetX = -1; ctx.shadowOffsetY = -1; ctx.shadowBlur = 10; ctx.fillText("SCORE " + score, CANVAS_WIDTH/2, 100); ctx.shadowOffsetX += 2; ctx.fillText("SCORE " + score, CANVAS_WIDTH/2, 100); ctx.shadowOffsetY += 2 ctx.fillText("SCORE " + score, CANVAS_WIDTH/2, 100); ctx.shadowOffsetX -= 2; ctx.fillText("SCORE " + score, CANVAS_WIDTH/2, 100); // # Display failure message. if (isStackFull() == true) { ctx.font = "bold 30px cambria"; ctx.fillStyle = '#ddd'; ctx.fillText("GAME OVER", CANVAS_WIDTH/2, 180); } } function loadNewImage() { img_background = new Image(); img_background.src = "images/" + IMAGE_PATHS[Math.floor(Math.random() * IMAGE_PATHS.length)]; } function initializeBoard() { // Initialize every elements of the board. // # Clear the stack. stack.length = STACK_DIMENSION; stack.fill(false); // # Reset the piece. resetPiece(); // # Reset the score. score = 0; } function updateBoard() { // Update the board after any change is made. // Check if the piece has landed on the stack if (isPieceLanded() == true) { // If so, merge the piece into the stack mergePieceIntoStack(); // Update the stack and get the result of the update. // -1 means full stack (game over), // 0 means no row has been cleared, // 1 or more means the number of rows that have been cleared. var result = updateStack(); // If you have cleared any row, raise the score and reset the piece. if (result != -1) { score += (result * STACK_COLUMNS * 10); resetPiece(); } } } function isPieceLanded() { var row, col, i_stack; // Iterate every block in the piece. for (var i = 0; i < PIECE_DIMENSION; i++) { if (piece[i] == true) { // Get the row, column position of the block. row = rowBlockInPiece(i); col = colBlockInPiece(i); // Check if landed on the floor. if (row == 0) return true; // Check if landed on another block in the stack. else (row <= STACK_ROWS) { // Check if there is any stack-block below the block. i_stack = posToIndexInStack(col, row - 1); if (stack[i_stack] == true) return true; } } } return false; } function mergePieceIntoStack() { var i_stack; var row, col; // Iterate every block in the piece. for (var i = 0; i < PIECE_DIMENSION; i++) { if (piece[i] == true) { // Merge the block into the stack. col = colBlockInPiece(i); row = rowBlockInPiece(i); i_stack = posToIndexInStack(col, row); if (i_stack < STACK_DIMENSION) { stack[i_stack] = true; } } } } function updateStack() { var row, n_cleared; // Check if you have full stack. if (isStackFull() == true) { // If so, return -1 as a result. return -1; } // Clear every full rows in the stack, and get the number. // Iterate every row in the stack. for (row = 0, n_cleared = 0; isRowEmpty(row) == false;) { // Check if the row is full. if (isRowFull(row) == true) { // If so, clear the row and raise the number. clearRow(row); n_cleared++; } // If not, check the upper row. else row++; } // return the number of rows that have been cleared. return n_cleared; } function isStackFull() { // Iterate every column in the stack. for (var i = 0; i < STACK_COLUMNS; i++) { // Check if the column is full. if (stack[STACK_DIMENSION - 1 - i] == true) { return true; } } return false; } function isRowEmpty(row) { var col, idx; // Iterate every position in the given row. for (col = 0; col < STACK_COLUMNS; col++) { // Check if there is any presence of block in the row. idx = posToIndexInStack(col, row); if (stack[idx] == true) return false; } return true; } function isRowFull(row) { var col, idx; // Iterate every position in the given row. for (col = 0; col < STACK_COLUMNS; col++) { // Check if there is any absence of block in the row. idx = posToIndexInStack(col, row); if (stack[idx] == false) return false; } return true; } function clearRow(row) { var topmost, col, idx; // Check if the row is the topmost one. topmost = true; if (row < STACK_ROWS - 1) { if (isRowEmpty(row + 1) == false) topmost = false; } // If the row is not the topmost one, if (topmost == false) { // Remove the given row. stack.splice(row * STACK_COLUMNS, STACK_COLUMNS); // Since the number of rows has decreased, make a new row. for (col = 0; col < STACK_COLUMNS; col++) { idx = posToIndexInStack(col, STACK_ROWS - 1); stack[idx] = false; } } // If the row is the topmost one, else { // Remove the given row. for (col = 0; col < STACK_COLUMNS; col++) { idx = posToIndexInStack(col, row); stack[idx] = false; } } } function resetPiece() { // Reset the piece according to the random type. var type = Math.floor(Math.random() * SAMPLE_SIZE); piece = Array.from(SAMPLES[type]); // Place the piece at the ceiling. pos_piece.x = Math.floor(STACK_COLUMNS / 2) - Math.floor(PIECE_COLUMNS/2); pos_piece.y = STACK_ROWS; } function movePiece(offset_x, offset_y) { // Check whether the moved piece makes an overlapping or not. if (isValidPiece(piece, pos_piece.x + offset_x, pos_piece.y + offset_y) == true) { // If not, move the piece. pos_piece.x += offset_x; pos_piece.y += offset_y; return true; } return false; } function rotatePiece(is_clockwise) { var rotated = []; var col, row; var x, y; var x_rotated, y_rotated; var col_rotated, row_rotated; var i_rotated; // The result of rotation will be kept in the 'rotated' array. rotated.length = PIECE_DIMENSION; rotated.fill(false); // Iterate every block in the piece. for (var i = 0; i < PIECE_DIMENSION; i++) { if (piece[i] == true) { // Get the row, column position of the block, relative to the left-bottom of the piece. col = i % PIECE_COLUMNS; row = Math.floor(i / PIECE_COLUMNS); // Get the new position of the block, relative to the center of the piece. x = col - Math.floor(PIECE_COLUMNS/2); y = row - Math.floor(PIECE_ROWS/2); // Rotated the position around the center of the piece. if (is_clockwise == true) { x_rotated = y; y_rotated = -x; } else { x_rotated = -y; y_rotated = x; } // Get the index at which the rotated block has to be placed. col_rotated = x_rotated + Math.floor(PIECE_COLUMNS/2); row_rotated = y_rotated + Math.floor(PIECE_ROWS/2); i_rotated = (row_rotated * PIECE_COLUMNS) + col_rotated; // Keep the result in the 'rotated' array. rotated[i_rotated] = true; } } // Check whether the 'rotated' array makes an overlapping or not. if (isValidPiece(rotated, pos_piece.x, pos_piece.y) == true) { // If not, apply the result to the piece. piece = Array.from(rotated); return true; } return false; } function isValidPiece(test, pos_x, pos_y) { var col, row, i_stack; /* test : a piece that will be checked if it makes an overlapping with another block in the stack. pos_x : column position of the piece. pos_y : row position of the piece. */ // Iterate every block in the test piece. for (var i = 0; i < PIECE_DIMENSION; i++) { if (test[i] == true) { // Get the row, column position of the block. col = pos_x + (i % PIECE_COLUMNS); row = pos_y + Math.floor(i / PIECE_COLUMNS); i_stack = posToIndexInStack(col, row); // Check if it makes an overlapping with the left wall. if (col < 0) return false; // Check if it makes an overlapping with the right wall. if (col > STACK_COLUMNS - 1) return false; // Check if it makes an overlapping with the floor. if (row < 0) return false; // Check if it makes an overlapping with another stack-block. if (i_stack < STACK_DIMENSION) { if (stack[i_stack] == true) return false; } } } return true; }