以下がテトリスのプログラムです。セキュリティの脆弱性を排除するため、evalや他のサイトへの遷移、リダイレクトは使用していません。また、面白いジョークとして、プログラムの開始時に「準備はいいかい?テトリス!」と表示するようにしています。
```
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Tetris</title>
<style>
body {
margin: 0;
padding: 0;
background-color: black;
color: white;
font-family: Arial, sans-serif;
text-align: center;
}
h1 {
font-size: 48px;
margin: 50px 0;
}
canvas {
border: 2px solid white;
}
</style>
</head>
<body>
<h1>準備はいいかい?テトリス!</h1>
<canvas id="canvas" width="240" height="480"></canvas>
<script>
// テトリスのブロック情報と色の定義
const blocks = [
[[0, 0], [1, 0], [0, 1], [1, 1]], // 四角
[[0, 0], [1, 0], [2, 0], [3, 0]], // 棒
[[0, 0], [1, 0], [2, 0], [1, 1]], // T字
[[0, 0], [1, 0], [2, 0], [2, 1]], // L字
[[0, 0], [1, 0], [2, 0], [0, 1]], // J字
[[1, 0], [2, 0], [0, 1], [1, 1]], // Z字
[[0, 0], [2, 0], [1, 1], [2, 1]] // 反転Z字
];
const colors = [
'#f00', // 赤
'#0f0', // 緑
'#00f', // 青
'#ff0', // 黄
'#f0f', // 紫
'#0ff', // シアン
'#fa0' // オレンジ
];
// キャンバスの設定
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.scale(20, 20);
// テトリスのスクリーンの高さと幅を定義
const screen = {
width: canvas.width / 20,
height: canvas.height / 20
};
// スコアやレベル、スピードなどの設定
const scoreText = document.createElement('div');
document.body.appendChild(scoreText);
let score = 0;
let level = 1;
let speed = 1000;
// テトリスの盤面を初期化する
const arena = [];
for (let y = 0; y < screen.height; ++y) {
const row = [];
for (let x = 0; x < screen.width; ++x) {
row.push(0);
}
arena.push(row);
}
// テトリスのブロックを上下左右に動かす関数
function moveBlock(deltaX, deltaY) {
player.x += deltaX;
player.y += deltaY;
if (collide(arena, player)) {
player.x -= deltaX;
player.y -= deltaY;
}
}
// テトリスの盤面に着地したブロックを固定する
function merge(arena, player) {
player.shape.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
arena[y + player.y][x + player.x] = value;
}
});
});
}
// テトリスのブロックが盤面と衝突しているかどうかを判定する
function collide(arena, player) {
const [m, o] = [player.shape, player];
for (let y = 0; y < m.length; ++y) {
for (let x = 0; x < m[y].length; ++x) {
if (m[y][x] !== 0 && (arena[y + o.y] && arena[y + o.y][x + o.x]) !== 0) {
return true;
}
}
}
return false;
}
// テトリスのブロックを回転する関数
function rotateShape(shape, direction) {
for (let y = 0; y < shape.length; ++y) {
for (let x = 0; x < y; ++x) {
[
shape[x][y],
shape[y][x]
] = [
shape[y][x],
shape[x][y]
];
}
}
if (direction > 0) {
shape.forEach(row => row.reverse());
} else {
shape.reverse();
}
}
// テトリスのブロックをランダムに生成する関数
function createBlock() {
const shape = blocks[Math.floor(Math.random() * blocks.length)];
const color = colors[Math.floor(Math.random() * colors.length)];
return {
shape,
color,
x: Math.floor((screen.width - shape[0].length) / 2),
y: 0
};
}
const player = createBlock();
let lastTime = 0;
let dropCounter = 0;
let gameOver = false;
// テトリスのメインループ
function update(time = 0) {
if (gameOver) {
return;
}
const deltaTime = time - lastTime;
lastTime = time;
dropCounter += deltaTime;
if (dropCounter > speed) {
moveBlock(0, 1);
dropCounter = 0;
}
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawArena();
drawBlock(player);
scoreText.innerHTML = `Score: ${score}<br>Level: ${level}`;
requestAnimationFrame(update);
}
// テトリスのブロックを描画する
function drawBlock(block) {
block.shape.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
ctx.fillStyle = block.color;
ctx.fillRect(block.x + x, block.y + y, 1, 1);
}
});
});
}
// テトリスの盤面を描画する
function drawArena() {
arena.forEach((row, y) => {
row.forEach((value, x) => {
if (value !== 0) {
ctx.fillStyle = colors[value - 1];
ctx.fillRect(x, y, 1, 1);
}
});
});
}
// キーイベントの定義
document.addEventListener('keydown', event => {
if (event.keyCode === 37) { // 左
moveBlock(-1, 0);
} else if (event.keyCode === 39) { // 右
moveBlock(1, 0);
} else if (event.keyCode === 40) { // 下
moveBlock(0, 1);
} else if (event.keyCode === 38) { // 上
rotateShape(player.shape, 1);
}
});
// テトリスのブロックが着地しているかどうかの判定
function checkForLines() {
let rowCount = 1;
outer: for (let y = arena.length - 1; y > 0; --y) {
for (let x = 0; x < arena[y].length; ++x) {
if (arena[y][x] === 0) {
continue outer;
}
}
const row = arena.splice(y, 1)[0].fill(0);
arena.unshift(row);
++y;
score += rowCount * 10;
rowCount *= 2;
}
}
// テトリスのゲームオーバー判定
function gameOverCheck() {
if (collide(arena, player)) {
gameOver = true;
alert('Game Over!');
}
}
// スピード、レベルの管理
function speedAndLevelUp() {
if (score >= 100 && level === 1) {
speed = 800;
level = 2;
} else if (score >= 200 && level === 2) {
speed = 600;
level = 3;
} else if (score >= 300 && level === 3) {
speed = 400;
level = 4;
} else if (score >= 400 && level === 4) {
speed = 200;
level = 5;
}
}
// メインループの開始
update();
setInterval(() => {
checkForLines();
gameOverCheck();
speedAndLevelUp();
}, 100);
</script>
</body>
</html>
```