Project 06: 轰炸座位表 (JS)
完整代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./style.css">
<script src="./index.js"></script>
<title>轰炸座位表</title>
</head>
<body>
<main>
<section id="control">
<input type="number" id="target" placeholder="人数">
<button id="start-button">开始</button>
</section>
<section id="seat-table"></section>
</main>
</body>
</html>
css
body {
margin: 0;
padding: 0;
}
#control {
display: flex;
justify-content: center;
gap: 1rem;
margin-top: 1rem;
}
#target {
width: 4rem;
text-align: center;
}
#seat-table {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem 0;
}
.row {
display: flex;
justify-content: center;
gap: 1rem;
}
.seat {
border: 1px dashed #999999;
padding: 0.5rem 1rem;
border-radius: 0.25rem;
transition: background-color 150ms ease, transform 300ms ease-in-out;
}
javascript
const rows = 8;
const cols = 6;
let target = 1;
const threshold = 4;
const seatTable = document.querySelector("#seat-table");
const heatMap = new Map();
for (let i = 0; i < rows; i++) {
const row = document.createElement("div");
row.className = "row";
seatTable.appendChild(row);
for (let j = 0; j < cols; j++) {
const seat = document.createElement("div");
seat.className = "seat";
seat.textContent = `${i + 1}/${j + 1}`;
row.appendChild(seat);
}
}
document.querySelector("#start-button").addEventListener('click', run);
async function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function run() {
let current = 0;
const newTarget = parseInt(document.querySelector("#target").value);
if (!isNaN(newTarget) && newTarget > 0) {
target = newTarget;
}
heatMap.clear();
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
const seat = seatTable.querySelector(`.row:nth-child(${i + 1}) .seat:nth-child(${j + 1})`);
seat.style.backgroundColor = "white";
seat.style.transform = "scale(1)";
}
}
while (current < target) {
await wait(45);
const randomRow = Math.floor(Math.random() * rows);
const randomCol = Math.floor(Math.random() * cols);
const seat = seatTable.querySelector(`.row:nth-child(${randomRow + 1}) .seat:nth-child(${randomCol + 1})`);
const id = `${randomRow},${randomCol}`;
if (!heatMap.has(id)) {
heatMap.set(id, 0);
}
const heat = heatMap.get(id) + 1;
if (heat > threshold) {
continue;
}
heatMap.set(id, heat);
const hue = heat === threshold ? 40 : ((heat === threshold - 1) ? 80 : 120);
const color = `hsl(${hue},50%,${100 - heat * 30 / threshold}%)`;
seat.style.backgroundColor = color;
if (heat >= threshold) {
seat.style.transform = "scale(1.2)";
current++;
}
}
await wait(300);
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
const id = `${i},${j}`;
if (heatMap.get(id) !== threshold) {
seatTable.querySelector(`.row:nth-child(${i + 1}) .seat:nth-child(${j + 1})`).style.backgroundColor = "white";
}
}
}
}