
本文讲解如何在基于 php session 的井字棋游戏中,精准识别并高亮显示构成胜利的三个格子,通过重构获胜检测逻辑与动态添加 css 类实现视觉反馈,兼顾可维护性与教学实用性。
本文讲解如何在基于 php session 的井字棋游戏中,精准识别并高亮显示构成胜利的三个格子,通过重构获胜检测逻辑与动态添加 css 类实现视觉反馈,兼顾可维护性与教学实用性。
要让井字棋中获胜的三个格子以不同颜色突出显示,关键在于分离「胜负判定」与「视图渲染」逻辑:不再依赖分散在各 isset($_GET['bX']) 分支中的硬编码判断,而是统一提取获胜位置索引(如 b1, b5, b9),再在 HTML 渲染阶段为对应按钮动态添加 CSS 类。
以下是完整、可直接集成到您原代码中的改进方案:
✅ 第一步:新增通用获胜检测函数
将原先散落在各 case 中的胜利逻辑,替换为一个清晰、可复用的函数。该函数接收当前棋盘数组,返回获胜格子的按钮编号数组(如 [1, 5, 9]):
function winningTiles(array $board): array
{
// 检查三行
for ($i = 0; $i < 3; $i++) {
if ($board[$i][0] !== SPACE &&
$board[$i][0] === $board[$i][1] &&
$board[$i][1] === $board[$i][2]) {
return [$i * 3 + 1, $i * 3 + 2, $i * 3 + 3];
}
}
// 检查三列
for ($i = 0; $i < 3; $i++) {
if ($board[0][$i] !== SPACE &&
$board[0][$i] === $board[1][$i] &&
$board[1][$i] === $board[2][$i]) {
return [$i + 1, $i + 4, $i + 7];
}
}
// 检查主对角线(左上→右下)
if ($board[0][0] !== SPACE &&
$board[0][0] === $board[1][1] &&
$board[1][1] === $board[2][2]) {
return [1, 5, 9];
}
// 检查副对角线(右上→左下)
if ($board[0][2] !== SPACE &&
$board[0][2] === $board[1][1] &&
$board[1][1] === $board[2][0]) {
return [3, 5, 7];
}
return []; // 无获胜者
}? 说明:SPACE 是您已定义的常量 " ";此函数不依赖全局状态,纯函数式设计,便于测试与复用。
立即学习“PHP免费学习笔记(深入)”;
✅ 第二步:在控制器末尾调用并存储获胜格子
在所有走棋逻辑执行完毕、胜负已知后(即 $winner !== NOWIN 或 $msg 已更新时),立即计算获胜格子列表,并存入 $_SESSION 或局部变量供视图使用:
// 在原有逻辑末尾(win() 调用之后或 tie 判定之后)插入:
$winningTiles = []; // 初始化为空
if ($winner !== NOWIN) {
$winningTiles = winningTiles($_SESSION['board']);
}
// 若为平局,$winningTiles 保持为空数组,不影响渲染✅ 第三步:重构 HTML 表单渲染,动态添加高亮类
删除原有 9 个独立 <input> 标签,改用嵌套循环生成,并根据 $winningTiles 数组决定是否添加 class="winningTile":
<style>
input {
height: 250px;
font-size: 5em;
border: 3px solid black;
padding: 20px;
margin-top: 5px;
margin-left: 5px;
}
.winningTile {
background-color: #ffcc00; /* 金色高亮,可自定义 */
box-shadow: 0 0 12px rgba(255, 204, 0, 0.7);
}
/* 可选:禁用状态下仍保留高亮色 */
input:disabled.winningTile {
background-color: #ffcc00 !important;
}
</style>
<form id="board" name="play" action="hw-ttt.php" method="get">
<?php
foreach ($_SESSION['board'] as $rowIndex => $row) {
foreach ($row as $colIndex => $cellValue) {
$buttonNumber = $rowIndex * 3 + $colIndex + 1;
$disabled = ($cellValue !== SPACE) ? ' disabled' : '';
$winClass = in_array($buttonNumber, $winningTiles) ? ' class="winningTile"' : '';
printf(
'<input type="submit" name="b%d" value="%s"%s%s>',
$buttonNumber,
htmlspecialchars($cellValue), // 防 XSS,重要!
$disabled,
$winClass
);
}
}
?>
</form>⚠️ 注意事项与最佳实践
- 安全性:务必对输出到 HTML 的 $cellValue 使用 htmlspecialchars(),防止 XSS 攻击(原代码未做此处理)。
- CSS 优先级:.winningTile 类需置于原始 input 样式之后,确保覆盖生效;若需更强控制,可加 !important(如上例所示)。
- 重置逻辑兼容性:$winningTiles 是每次页面加载时实时计算的,因此“Play Again”按钮触发 session_destroy() 后,新局自然无高亮,无需额外清理。
- 可扩展性:未来若需支持多种获胜主题(如 X 红色 / O 蓝色),只需修改 winningTiles() 返回值后,在循环中根据 $cellValue 动态设置 class="winningX" 或 class="winningO" 即可。
通过以上三步改造,您的井字棋将具备精准、语义清晰且易于维护的获胜高亮功能——既满足作业要求,也体现了良好的分层设计思想。



















