<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>深红色井字棋</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #1a0000 0%, #330000 30%, #4d0000 60%, #2a0000 100%);
font-family: 'Georgia', 'Times New Roman', serif;
color: #f5e6e6;
overflow: hidden;
}
.container {
text-align: center;
position: relative;
}
h1 {
font-size: 2.8em;
margin-bottom: 10px;
color: #ff4444;
text-shadow: 0 0 20px rgba(255, 50, 50, 0.5), 0 0 40px rgba(255, 30, 30, 0.3);
letter-spacing: 4px;
}
.status {
font-size: 1.3em;
margin-bottom: 25px;
color: #ffcccc;
min-height: 40px;
display: flex;
align-items: center;
justify-content: center;
text-shadow: 0 0 10px rgba(255, 100, 100, 0.4);
}
.status.winner {
color: #ff6666;
font-weight: bold;
animation: pulse 1s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.board {
display: grid;
grid-template-columns: repeat(3, 120px);
grid-template-rows: repeat(3, 120px);
gap: 8px;
margin: 0 auto 30px;
padding: 15px;
background: rgba(100, 0, 0, 0.3);
border-radius: 15px;
box-shadow: 0 0 30px rgba(150, 0, 0, 0.4), inset 0 0 20px rgba(80, 0, 0, 0.3);
border: 2px solid rgba(200, 50, 50, 0.3);
}
.cell {
width: 120px;
height: 120px;
background: rgba(60, 0, 0, 0.6);
border: 2px solid rgba(180, 40, 40, 0.4);
border-radius: 12px;
display: flex;
justify-content: center;
align-items: center;
font-size: 3em;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.cell::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 100, 100, 0.1), transparent);
transition: left 0.5s;
}
.cell:hover::before {
left: 100%;
}
.cell:hover:not(.taken) {
background: rgba(120, 0, 0, 0.7);
border-color: rgba(220, 60, 60, 0.6);
box-shadow: 0 0 15px rgba(200, 50, 50, 0.3);
transform: scale(1.03);
}
.cell.taken {
cursor: not-allowed;
}
.cell.x {
color: #ff6b6b;
text-shadow: 0 0 15px rgba(255, 100, 100, 0.6), 0 0 30px rgba(255, 60, 60, 0.3);
animation: appear 0.3s ease-out;
}
.cell.o {
color: #ffaa7f;
text-shadow: 0 0 15px rgba(255, 170, 127, 0.6), 0 0 30px rgba(255, 140, 100, 0.3);
animation: appear 0.3s ease-out;
}
@keyframes appear {
0% {
transform: scale(0) rotate(180deg);
opacity: 0;
}
50% {
transform: scale(1.2) rotate(-10deg);
}
100% {
transform: scale(1) rotate(0deg);
opacity: 1;
}
}
.cell.win {
background: rgba(180, 30, 30, 0.8);
border-color: #ff4444;
animation: winGlow 0.8s ease-in-out infinite alternate;
}
@keyframes winGlow {
0% {
box-shadow: 0 0 10px rgba(255, 50, 50, 0.5);
}
100% {
box-shadow: 0 0 30px rgba(255, 50, 50, 0.9), 0 0 60px rgba(255, 30, 30, 0.5);
}
}
.scoreboard {
display: flex;
justify-content: center;
gap: 40px;
margin-bottom: 25px;
font-size: 1.1em;
}
.score {
padding: 8px 20px;
background: rgba(80, 0, 0, 0.5);
border-radius: 8px;
border: 1px solid rgba(180, 40, 40, 0.3);
}
.score span {
font-weight: bold;
color: #ff8888;
}
.restart-btn {
padding: 12px 35px;
font-size: 1.1em;
font-family: 'Georgia', serif;
background: linear-gradient(135deg, #8b0000, #a52a2a);
color: #ffe0e0;
border: 2px solid #cc3333;
border-radius: 10px;
cursor: pointer;
transition: all 0.3s ease;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0 4px 15px rgba(139, 0, 0, 0.4);
letter-spacing: 1px;
}
.restart-btn:hover {
background: linear-gradient(135deg, #a52a2a, #cc3333);
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(180, 30, 30, 0.6);
border-color: #ff4444;
}
.restart-btn:active {
transform: translateY(0);
box-shadow: 0 2px 10px rgba(139, 0, 0, 0.4);
}
.particles {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1;
}
.particle {
position: absolute;
width: 4px;
height: 4px;
background: rgba(255, 80, 80, 0.4);
border-radius: 50%;
animation: float linear infinite;
}
@keyframes float {
0% {
transform: translateY(100vh) rotate(0deg);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(-10vh) rotate(720deg);
opacity: 0;
}
}
</style>
</head>
<body>
<div class="particles" id="particles"></div>
<div class="container">
<h1>⚔ 井 字 棋 ⚔</h1>
<div class="scoreboard">
<div class="score">玩家 X: <span id="scoreX">0</span></div>
<div class="score">平局: <span id="scoreDraw">0</span></div>
<div class="score">玩家 O: <span id="scoreO">0</span></div>
</div>
<div class="status" id="status">轮到玩家 X</div>
<div class="board" id="board">
<div class="cell" data-index="0"></div>
<div class="cell" data-index="1"></div>
<div class="cell" data-index="2"></div>
<div class="cell" data-index="3"></div>
<div class="cell" data-index="4"></div>
<div class="cell" data-index="5"></div>
<div class="cell" data-index="6"></div>
<div class="cell" data-index="7"></div>
<div class="cell" data-index="8"></div>
</div>
<button class="restart-btn" id="restartBtn">重新开始</button>
</div>
<script>
const cells = document.querySelectorAll('.cell');
const statusEl = document.getElementById('status');
const restartBtn = document.getElementById('restartBtn');
const scoreXEl = document.getElementById('scoreX');
const scoreOEl = document.getElementById('scoreO');
const scoreDrawEl = document.getElementById('scoreDraw');
let board = ['', '', '', '', '', '', '', '', ''];
let currentPlayer = 'X';
let gameActive = true;
let scores = { X: 0, O: 0, draw: 0 };
const winConditions = [
[0, 1, 2], [3, 4, 5], [6, 7, 8],
[0, 3, 6], [1, 4, 7], [2, 5, 8],
[0, 4, 8], [2, 4, 6]
];
function checkWinner() {
for (let condition of winConditions) {
const [a, b, c] = condition;
if (board[a] && board[a] === board[b] && board[a] === board[c]) {
return { winner: board[a], line: condition };
}
}
if (!board.includes('')) {
return { winner: 'draw', line: [] };
}
return null;
}
function updateDisplay() {
cells.forEach((cell, index) => {
cell.textContent = board[index];
if (board[index]) {
cell.classList.add('taken', board[index].toLowerCase());
}
});
}
function handleCellClick(e) {
const index = parseInt(e.target.dataset.index);
if (board[index] || !gameActive) return;
board[index] = currentPlayer;
updateDisplay();
const result = checkWinner();
if (result) {
gameActive = false;
if (result.winner === 'draw') {
statusEl.textContent = '平局!';
statusEl.classList.add('winner');
scores.draw++;
scoreDrawEl.textContent = scores.draw;
} else {
statusEl.textContent = `🎉 玩家 ${result.winner} 获胜!🎉`;
statusEl.classList.add('winner');
scores[result.winner]++;
if (result.winner === 'X') scoreXEl.textContent = scores.X;
else scoreOEl.textContent = scores.O;
result.line.forEach(i => {
cells[i].classList.add('win');
});
}
} else {
currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
statusEl.textContent = `轮到玩家 ${currentPlayer}`;
}
}
function restartGame() {
board = ['', '', '', '', '', '', '', '', ''];
gameActive = true;
currentPlayer = 'X';
statusEl.textContent = '轮到玩家 X';
statusEl.classList.remove('winner');
cells.forEach(cell => {
cell.className = 'cell';
cell.textContent = '';
});
}
cells.forEach(cell => cell.addEventListener('click', handleCellClick));
restartBtn.addEventListener('click', restartGame);
// Create floating particles
const particlesContainer = document.getElementById('particles');
for (let i = 0; i < 20; i++) {
const particle = document.createElement('div');
particle.className = 'particle';
particle.style.left = Math.random() * 100 + '%';
particle.style.animationDuration = (Math.random() * 10 + 8) + 's';
particle.style.animationDelay = Math.random() * 10 + 's';
particle.style.width = (Math.random() * 4 + 2) + 'px';
particle.style.height = particle.style.width;
particlesContainer.appendChild(particle);
}
</script>
</body>
</html>
index.html
md
README.md
index.html