VCHS Computer Science
Computer Science at Valley Catholic High School
Pages
Home
APCSA
APCSP
Ten Commandments
Jump
Tetris Part 3
Source Code
<!-- CSS --> <style> #grid { background-color: black; position: relative; border-right: solid 1px black; border-bottom: solid 1px black; } .block { position: absolute; border: solid 1px silver; } </style> <!-- HTML --> <div id="grid" style="height: 400px; width: 250px;"><div class="block" style="height: 25px; width: 25px; background-color: purple; left: 100px; top: 0px;"></div><div class="block" style="height: 25px; width: 25px; background-color: purple; left: 125px; top: 0px;"></div><div class="block" style="height: 25px; width: 25px; background-color: purple; left: 100px; top: 25px;"></div><div class="block" style="height: 25px; width: 25px; background-color: purple; left: 125px; top: 25px;"></div></div> <!-- JavaScript --> <script> (function IIFE() { // Immediately Invoked Function Expression "use strict"; // Opt into strict mode. (Opt out of sloppy mode.) /*** GLOBAL VARIABLE ***/ let currentShape; /*** GLOBAL CONSTANTS ***/ const frozenBlocks = []; // Unit Constants const unitConst = Object.freeze({ units: "px", qtyPer: 25 }); // Block Constants const blockConst = { unitsWide: unitConst.qtyPer, unitsTall: unitConst.qtyPer, length: unitConst.qtyPer + unitConst.units }; blockConst.width = blockConst.length; blockConst.height = blockConst.length; Object.freeze(blockConst); // Grid Constants const gridConst = { blocksWide: 10, blocksTall: 16 }; gridConst.width = (gridConst.blocksWide * blockConst.unitsWide) + unitConst.units; gridConst.height = (gridConst.blocksTall * blockConst.unitsTall) + unitConst.units; Object.freeze(gridConst); // Element Constants const elemConst = Object.freeze({ grid: getSizedGrid() }); // Shape Constants const shapeConst = Object.freeze({ LColor: "orange", JColor: "red", SColor: "royalblue", ZColor: "gold", TColor: "green", IColor: "hotpink", OColor: "purple" }); /*** FUNCTIONS ***/ function isBlockedAt(left, top) { const n = frozenBlocks.length; for (let i = 0; i < n; ++i) { const block = frozenBlocks[i]; if (block.left() === left && block.top() === top) return true; } return false; } /** Gets, sets the size of, and returns the grid element. */ function getSizedGrid() { const grid = document.getElementById("grid"); grid.style.height = gridConst.height; grid.style.width = gridConst.width; return grid; } /** Constructs a single block object. */ function Block(options) { // Initialize the new block. const thisObject = this; const element = createBlockElement(); let currentLeft = options.left; let currentTop = options.top; updatePosition(); /* Private Functions */ function updateLeft() { element.style.left = (currentLeft * blockConst.unitsWide) + unitConst.units; } function updateTop() { element.style.top = (currentTop * blockConst.unitsTall) + unitConst.units; } function updatePosition() { updateLeft(); updateTop(); } function createBlockElement() { const block = document.createElement("div"); block.classList.add("block"); block.style.height = blockConst.height; block.style.width = blockConst.width; block.style.backgroundColor = options.bgColor; return block; } function canMoveLeft() { return currentLeft > 0 && !isBlockedAt(currentLeft - 1, currentTop); } function canMoveRight() { return currentLeft < gridConst.blocksWide - 1 && !isBlockedAt(currentLeft + 1, currentTop); } function canMoveDown() { return currentTop < gridConst.blocksTall - 1 && !isBlockedAt(currentLeft, currentTop + 1); } function moveLeft() { --currentLeft; updateLeft(); } function moveRight() { ++currentLeft; updateLeft(); } function moveDown() { ++currentTop; updateTop(); } /* Public Methods */ this.addTo = function(otherElement) { otherElement.append(element); return thisObject; }; this.moveLeft = function() { if (canMoveLeft()) moveLeft(); return thisObject; }; this.moveRight = function() { if (canMoveRight()) moveRight(); return thisObject; }; this.moveDown = function() { if (canMoveDown()) moveDown(); return thisObject; }; this.canMoveRight = canMoveRight; this.canMoveLeft = canMoveLeft; this.canMoveDown = canMoveDown; this.left = function() { return currentLeft; } this.top = function() { return currentTop; } this.setLeft = function(value) { currentLeft = value; updateLeft(); } this.setTop = function(value) { currentTop = value; updateTop(); } } function onKeyDown(event) { const key = event.key; if (key === "ArrowLeft") { currentShape.moveLeft(); event.preventDefault(); } else if (key === "ArrowRight") { currentShape.moveRight(); event.preventDefault(); } else if (key === "ArrowDown") { currentShape.moveDown(); event.preventDefault(); } else if (key === "ArrowUp") { currentShape.pivot(); event.preventDefault(); } } /** Base class for a shape object consisting of blocks. */ function Shape(blocks, p) { const thisObject = this; const numBlocks = blocks.length; const pivotBlock = (p === undefined) ? undefined : blocks[p]; blocks.forEach(function(block) { block.addTo(elemConst.grid); }); function canMoveRight() { for (let i = 0; i < numBlocks; ++i) { if (!blocks[i].canMoveRight()) return false; } return true; } function canMoveLeft() { for (let i = 0; i < numBlocks; ++i) { if (!blocks[i].canMoveLeft()) return false; } return true; } function canMoveDown() { for (let i = 0; i < numBlocks; ++i) { if (!blocks[i].canMoveDown()) return false; } return true; } function canPivot() { return true; } function moveDown() { for (let i = 0; i < numBlocks; ++i) blocks[i].moveDown(); } function moveLeft() { for (let i = 0; i < numBlocks; ++i) blocks[i].moveLeft(); } function moveRight() { for (let i = 0; i < numBlocks; ++i) blocks[i].moveRight(); } function freeze() { blocks.forEach(function(block) { frozenBlocks.push(block); }); currentShape = getNextShape(); } function pivot(block) { // Credit: https://www.youtube.com/watch?v=Atlr5vvdchY if (block === pivotBlock || pivotBlock === undefined) return; const B = [block.top(), block.left()]; const P = [pivotBlock.top(), pivotBlock.left()]; const Vr = [B[0] - P[0], B[1] - P[1]]; const Vt = [-1 * Vr[1], Vr[0]]; const N = [Vt[0] + P[0], Vt[1] + P[1]]; block.setTop(N[0]); block.setLeft(N[1]); } this.moveDown = function() { if (canMoveDown()) moveDown(); else freeze(); return thisObject; }; this.moveLeft = function() { if (canMoveLeft()) moveLeft(); return thisObject; }; this.moveRight = function() { if (canMoveRight()) moveRight(); return thisObject; }; this.canMoveRight = canMoveRight; this.canMoveLeft = canMoveLeft; this.canMoveDown = canMoveDown; this.freeze = freeze; this.pivot = function() { if (canPivot()) blocks.forEach(pivot); return thisObject; } } /* Shape Subclasses */ function LShape() { Shape.call(this, getBlocks(), 1); function getBlocks() { const color = shapeConst.LColor; const blocks = []; blocks.push(new Block({bgColor: color, left: 3, top: 1})); blocks.push(new Block({bgColor: color, left: 4, top: 1})); blocks.push(new Block({bgColor: color, left: 5, top: 1})); blocks.push(new Block({bgColor: color, left: 5, top: 0})); return blocks; } } function JShape() { Shape.call(this, getBlocks(), 1); function getBlocks() { const color = shapeConst.JColor; const blocks = []; blocks.push(new Block({bgColor: color, left: 3, top: 0})); blocks.push(new Block({bgColor: color, left: 4, top: 0})); blocks.push(new Block({bgColor: color, left: 5, top: 0})); blocks.push(new Block({bgColor: color, left: 5, top: 1})); return blocks; } } function SShape() { Shape.call(this, getBlocks(), 2); function getBlocks() { const color = shapeConst.SColor; const blocks = []; blocks.push(new Block({bgColor: color, left: 4, top: 0})); blocks.push(new Block({bgColor: color, left: 5, top: 0})); blocks.push(new Block({bgColor: color, left: 5, top: 1})); blocks.push(new Block({bgColor: color, left: 6, top: 1})); return blocks; } } function ZShape() { Shape.call(this, getBlocks(), 2); function getBlocks() { const color = shapeConst.ZColor; const blocks = []; blocks.push(new Block({bgColor: color, left: 4, top: 1})); blocks.push(new Block({bgColor: color, left: 5, top: 1})); blocks.push(new Block({bgColor: color, left: 5, top: 0})); blocks.push(new Block({bgColor: color, left: 6, top: 0})); return blocks; } } function TShape() { Shape.call(this, getBlocks(), 1); function getBlocks() { const color = shapeConst.TColor; const blocks = []; blocks.push(new Block({bgColor: color, left: 3, top: 1})); blocks.push(new Block({bgColor: color, left: 4, top: 1})); blocks.push(new Block({bgColor: color, left: 5, top: 1})); blocks.push(new Block({bgColor: color, left: 4, top: 0})); return blocks; } } function OShape() { Shape.call(this, getBlocks(), undefined); function getBlocks() { const color = shapeConst.OColor; const blocks = []; blocks.push(new Block({bgColor: color, left: 4, top: 0})); blocks.push(new Block({bgColor: color, left: 5, top: 0})); blocks.push(new Block({bgColor: color, left: 4, top: 1})); blocks.push(new Block({bgColor: color, left: 5, top: 1})); return blocks; } } function IShape() { Shape.call(this, getBlocks(), 2); function getBlocks() { const color = shapeConst.IColor; const blocks = []; blocks.push(new Block({bgColor: color, left: 3, top: 0})); blocks.push(new Block({bgColor: color, left: 4, top: 0})); blocks.push(new Block({bgColor: color, left: 5, top: 0})); blocks.push(new Block({bgColor: color, left: 6, top: 0})); return blocks; } } function getNextShape() { const fxns = [LShape, JShape, SShape, ZShape, TShape, OShape, IShape]; const index = Math.floor(Math.random() * fxns.length); const fxn = fxns[index]; return new fxn(); } function startGame() { currentShape = getNextShape(); } /*** MAIN ***/ window.addEventListener("keydown", onKeyDown); startGame(); })(); </script>
Newer Post
Older Post
Home