← back to Model Arena
data/artifacts/04692f72ef1d/kimi.html
495 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tetris</title>
<style>
body {
margin: 0;
padding: 0;
background: #111;
color: #fff;
font-family: 'Courier New', Courier, monospace;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
overflow: hidden;
}
#gameContainer {
display: flex;
gap: 20px;
background: #222;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 20px rgba(0,0,0,0.8);
}
#board {
border: 3px solid #444;
background: #000;
}
#sidePanel {
display: flex;
flex-direction: column;
gap: 20px;
width: 120px;
}
#nextCanvas {
border: 2px solid #444;
background: #000;
}
.infoBox {
background: #333;
padding: 10px;
border-radius: 4px;
text-align: center;
border: 1px solid #555;
}
.label {
font-size: 12px;
color: #888;
text-transform: uppercase;
margin-bottom: 5px;
}
.value {
font-size: 20px;
font-weight: bold;
color: #fff;
}
#controls {
font-size: 11px;
color: #666;
line-height: 1.5;
margin-top: auto;
}
#gameOver, #paused {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0,0,0,0.9);
padding: 30px;
border-radius: 8px;
text-align: center;
border: 2px solid #fff;
display: none;
}
button {
background: #4a4;
color: white;
border: none;
padding: 10px 20px;
font-family: inherit;
font-size: 16px;
cursor: pointer;
margin-top: 10px;
border-radius: 4px;
}
button:hover {
background: #5c5;
}
h1 {
margin: 0 0 10px 0;
font-size: 24px;
text-shadow: 2px 2px 0 #f00;
}
</style>
</head>
<body>
<div id="gameContainer">
<canvas id="board" width="300" height="600"></canvas>
<div id="sidePanel">
<div class="infoBox">
<div class="label">Next</div>
<canvas id="nextCanvas" width="120" height="120"></canvas>
</div>
<div class="infoBox">
<div class="label">Score</div>
<div class="value" id="score">0</div>
</div>
<div class="infoBox">
<div class="label">Lines</div>
<div class="value" id="lines">0</div>
</div>
<div class="infoBox">
<div class="label">Level</div>
<div class="value" id="level">1</div>
</div>
<div id="controls">
<strong>Controls:</strong><br>
← → : Move<br>
↑ / X : Rotate<br>
Z : Rotate CCW<br>
↓ : Soft Drop<br>
Space : Hard Drop<br>
P : Pause<br>
R : Restart
</div>
</div>
</div>
<div id="gameOver">
<h1>GAME OVER</h1>
<div>Score: <span id="finalScore">0</span></div>
<button onclick="resetGame()">Restart</button>
</div>
<div id="paused">
<h1>PAUSED</h1>
<div>Press P to resume</div>
</div>
<script>
const canvas = document.getElementById('board');
const ctx = canvas.getContext('2d');
const nextCanvas = document.getElementById('nextCanvas');
const nextCtx = nextCanvas.getContext('2d');
const COLS = 10;
const ROWS = 20;
const BLOCK_SIZE = 30;
const PREVIEW_BLOCK_SIZE = 25;
let board = [];
let score = 0;
let lines = 0;
let level = 1;
let gameOver = false;
let paused = false;
let dropCounter = 0;
let lastTime = 0;
let dropInterval = 1000;
const PIECES = [
{ shape: [[1,1,1,1]], color: '#00f0f0' }, // I
{ shape: [[1,1],[1,1]], color: '#f0f000' }, // O
{ shape: [[0,1,0],[1,1,1]], color: '#a000f0' }, // T
{ shape: [[0,1,1],[1,1,0]], color: '#00f000' }, // S
{ shape: [[1,1,0],[0,1,1]], color: '#f00000' }, // Z
{ shape: [[1,0,0],[1,1,1]], color: '#0000f0' }, // J
{ shape: [[0,0,1],[1,1,1]], color: '#f0a000' } // L
];
let currentPiece = null;
let nextPiece = null;
function createBoard() {
board = Array(ROWS).fill().map(() => Array(COLS).fill(0));
}
function rotateMatrix(matrix, times) {
times = ((times % 4) + 4) % 4;
let result = matrix;
for (let i = 0; i < times; i++) {
result = rotate90(result);
}
return result;
}
function rotate90(matrix) {
const rows = matrix.length;
const cols = matrix[0].length;
const rotated = [];
for (let i = 0; i < cols; i++) {
rotated[i] = [];
for (let j = 0; j < rows; j++) {
rotated[i][j] = matrix[rows - 1 - j][i];
}
}
return rotated;
}
function getRandomPiece() {
const piece = PIECES[Math.floor(Math.random() * PIECES.length)];
return {
shape: piece.shape,
color: piece.color,
x: 0,
y: 0,
rotation: 0
};
}
function spawnPiece() {
currentPiece = nextPiece || getRandomPiece();
nextPiece = getRandomPiece();
const shape = rotateMatrix(currentPiece.shape, currentPiece.rotation);
currentPiece.x = Math.floor(COLS / 2) - Math.floor(shape[0].length / 2);
currentPiece.y = 0;
if (!isValidPosition(currentPiece, currentPiece.x, currentPiece.y, currentPiece.rotation)) {
endGame();
}
}
function isValidPosition(piece, x, y, rotation) {
const shape = rotateMatrix(piece.shape, rotation);
for (let r = 0; r < shape.length; r++) {
for (let c = 0; c < shape[r].length; c++) {
if (shape[r][c]) {
const newX = x + c;
const newY = y + r;
if (newX < 0 || newX >= COLS || newY >= ROWS) return false;
if (newY >= 0 && board[newY][newX]) return false;
}
}
}
return true;
}
function rotatePiece(clockwise = true) {
const newRotation = clockwise ? (currentPiece.rotation + 1) % 4 : (currentPiece.rotation + 3) % 4;
const kicks = [0, -1, 1, -2, 2];
for (let kick of kicks) {
if (isValidPosition(currentPiece, currentPiece.x + kick, currentPiece.y, newRotation)) {
currentPiece.x += kick;
currentPiece.rotation = newRotation;
break;
}
}
}
function movePiece(dx, dy) {
if (isValidPosition(currentPiece, currentPiece.x + dx, currentPiece.y + dy, currentPiece.rotation)) {
currentPiece.x += dx;
currentPiece.y += dy;
return true;
}
return false;
}
function dropPiece() {
if (!movePiece(0, 1)) {
lockPiece();
}
dropCounter = 0;
}
function hardDrop() {
while (movePiece(0, 1)) {
score += 2;
}
lockPiece();
dropCounter = 0;
}
function lockPiece() {
const shape = rotateMatrix(currentPiece.shape, currentPiece.rotation);
for (let r = 0; r < shape.length; r++) {
for (let c = 0; c < shape[r].length; c++) {
if (shape[r][c]) {
const y = currentPiece.y + r;
const x = currentPiece.x + c;
if (y >= 0) {
board[y][x] = currentPiece.color;
}
}
}
}
clearLines();
spawnPiece();
updateStats();
}
function clearLines() {
let linesCleared = 0;
for (let r = ROWS - 1; r >= 0; r--) {
if (board[r].every(cell => cell !== 0)) {
board.splice(r, 1);
board.unshift(Array(COLS).fill(0));
linesCleared++;
r++;
}
}
if (linesCleared > 0) {
lines += linesCleared;
const points = [0, 100, 300, 500, 800];
score += points[linesCleared] * level;
level = Math.floor(lines / 10) + 1;
dropInterval = Math.max(100, 1000 - (level - 1) * 80);
}
}
function drawBlock(context, x, y, color, size = BLOCK_SIZE) {
context.fillStyle = color;
context.fillRect(x * size, y * size, size, size);
context.strokeStyle = 'rgba(255,255,255,0.4)';
context.lineWidth = 2;
context.strokeRect(x * size, y * size, size, size);
context.fillStyle = 'rgba(255,255,255,0.3)';
context.fillRect(x * size + 2, y * size + 2, size - 4, 3);
context.fillStyle = 'rgba(0,0,0,0.2)';
context.fillRect(x * size + 2, y * size + size - 5, size - 4, 3);
}
function draw() {
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = '#222';
ctx.lineWidth = 1;
for (let i = 0; i <= COLS; i++) {
ctx.beginPath();
ctx.moveTo(i * BLOCK_SIZE, 0);
ctx.lineTo(i * BLOCK_SIZE, canvas.height);
ctx.stroke();
}
for (let i = 0; i <= ROWS; i++) {
ctx.beginPath();
ctx.moveTo(0, i * BLOCK_SIZE);
ctx.lineTo(canvas.width, i * BLOCK_SIZE);
ctx.stroke();
}
for (let r = 0; r < ROWS; r++) {
for (let c = 0; c < COLS; c++) {
if (board[r][c]) {
drawBlock(ctx, c, r, board[r][c]);
}
}
}
if (currentPiece) {
const shape = rotateMatrix(currentPiece.shape, currentPiece.rotation);
for (let r = 0; r < shape.length; r++) {
for (let c = 0; c < shape[r].length; c++) {
if (shape[r][c]) {
drawBlock(ctx, currentPiece.x + c, currentPiece.y + r, currentPiece.color);
}
}
}
}
if (nextPiece) {
nextCtx.fillStyle = '#000';
nextCtx.fillRect(0, 0, nextCanvas.width, nextCanvas.height);
const shape = nextPiece.shape;
const offsetX = Math.floor((4 - shape[0].length) / 2);
const offsetY = Math.floor((4 - shape.length) / 2);
for (let r = 0; r < shape.length; r++) {
for (let c = 0; c < shape[r].length; c++) {
if (shape[r][c]) {
drawBlock(nextCtx, offsetX + c, offsetY + r, nextPiece.color, PREVIEW_BLOCK_SIZE);
}
}
}
}
}
function update(time = 0) {
if (gameOver || paused) return;
const deltaTime = time - lastTime;
lastTime = time;
dropCounter += deltaTime;
if (dropCounter > dropInterval) {
dropPiece();
}
draw();
requestAnimationFrame(update);
}
function updateStats() {
document.getElementById('score').textContent = score;
document.getElementById('lines').textContent = lines;
document.getElementById('level').textContent = level;
}
function endGame() {
gameOver = true;
document.getElementById('finalScore').textContent = score;
document.getElementById('gameOver').style.display = 'block';
}
function resetGame() {
createBoard();
score = 0;
lines = 0;
level = 1;
dropInterval = 1000;
gameOver = false;
paused = false;
currentPiece = null;
nextPiece = null;
document.getElementById('gameOver').style.display = 'none';
document.getElementById('paused').style.display = 'none';
updateStats();
spawnPiece();
lastTime = 0;
dropCounter = 0;
update();
}
function togglePause() {
if (gameOver) return;
paused = !paused;
document.getElementById('paused').style.display = paused ? 'block' : 'none';
if (!paused) {
lastTime = performance.now();
update();
}
}
document.addEventListener('keydown', (e) => {
if (e.key === 'r' || e.key === 'R') {
if (gameOver) resetGame();
return;
}
if (gameOver) return;
if (e.key === 'p' || e.key === 'P') {
togglePause();
return;
}
if (paused) return;
switch(e.key) {
case 'ArrowLeft':
if (movePiece(-1, 0)) draw();
break;
case 'ArrowRight':
if (movePiece(1, 0)) draw();
break;
case 'ArrowDown':
if (movePiece(0, 1)) {
score += 1;
updateStats();
draw();
}
break;
case 'ArrowUp':
case 'x':
case 'X':
rotatePiece(true);
draw();
break;
case 'z':
case 'Z':
rotatePiece(false);
draw();
break;
case ' ':
hardDrop();
updateStats();
draw();
break;
}
});
createBoard();
spawnPiece();
updateStats();
update();
</script>
</body>
</html>