225 lines
5.8 KiB
PHP
225 lines
5.8 KiB
PHP
<?php
|
||
|
||
/**
|
||
* 文件功能:五子棋对局模型
|
||
*
|
||
* 管理 PvP(玩家对战)和 PvE(人机对战)两种模式的对局记录。
|
||
* 提供棋盘操作、胜负判断及状态管理方法。
|
||
*
|
||
* @author ChatRoom Laravel
|
||
*
|
||
* @version 1.0.0
|
||
*/
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||
|
||
class GomokuGame extends Model
|
||
{
|
||
protected $fillable = [
|
||
'mode',
|
||
'room_id',
|
||
'player_black_id',
|
||
'player_white_id',
|
||
'ai_level',
|
||
'status',
|
||
'board',
|
||
'current_turn',
|
||
'winner',
|
||
'moves_history',
|
||
'reward_gold',
|
||
'entry_fee',
|
||
'invite_expires_at',
|
||
'started_at',
|
||
'finished_at',
|
||
];
|
||
|
||
/**
|
||
* 属性类型转换。
|
||
*/
|
||
protected function casts(): array
|
||
{
|
||
return [
|
||
'board' => 'array',
|
||
'moves_history' => 'array',
|
||
'invite_expires_at' => 'datetime',
|
||
'started_at' => 'datetime',
|
||
'finished_at' => 'datetime',
|
||
];
|
||
}
|
||
|
||
// ─── 关联 ─────────────────────────────────────────────────────────
|
||
|
||
/**
|
||
* 黑棋玩家(发起方)。
|
||
*/
|
||
public function playerBlack(): BelongsTo
|
||
{
|
||
return $this->belongsTo(User::class, 'player_black_id');
|
||
}
|
||
|
||
/**
|
||
* 白棋玩家(PvP 接受方)。
|
||
*/
|
||
public function playerWhite(): BelongsTo
|
||
{
|
||
return $this->belongsTo(User::class, 'player_white_id');
|
||
}
|
||
|
||
/**
|
||
* 所属聊天室。
|
||
*/
|
||
public function room(): BelongsTo
|
||
{
|
||
return $this->belongsTo(Room::class);
|
||
}
|
||
|
||
// ─── 棋盘操作 ─────────────────────────────────────────────────────
|
||
|
||
/**
|
||
* 生成空白 15×15 棋盘(全 0)。
|
||
*/
|
||
public static function emptyBoard(): array
|
||
{
|
||
return array_fill(0, 15, array_fill(0, 15, 0));
|
||
}
|
||
|
||
/**
|
||
* 在指定坐标落子,返回新棋盘状态。
|
||
*
|
||
* @param array $board 当前棋盘
|
||
* @param int $row 行(0-14)
|
||
* @param int $col 列(0-14)
|
||
* @param int $color 棋子颜色(1=黑 2=白)
|
||
*/
|
||
public static function placeStone(array $board, int $row, int $col, int $color): array
|
||
{
|
||
$board[$row][$col] = $color;
|
||
|
||
return $board;
|
||
}
|
||
|
||
/**
|
||
* 检查指定坐标是否已有棋子。
|
||
*
|
||
* @param array $board 棋盘
|
||
* @param int $row 行
|
||
* @param int $col 列
|
||
*/
|
||
public static function isOccupied(array $board, int $row, int $col): bool
|
||
{
|
||
return ($board[$row][$col] ?? 0) !== 0;
|
||
}
|
||
|
||
/**
|
||
* 判断在指定坐标落子后,该颜色是否已连成五子。
|
||
*
|
||
* @param array $board 落子后的棋盘
|
||
* @param int $row 最后落子行
|
||
* @param int $col 最后落子列
|
||
* @param int $color 棋子颜色(1=黑 2=白)
|
||
*/
|
||
public static function checkWin(array $board, int $row, int $col, int $color): bool
|
||
{
|
||
// 四个方向:横、竖、左斜、右斜
|
||
$directions = [[0, 1], [1, 0], [1, 1], [1, -1]];
|
||
|
||
foreach ($directions as [$dr, $dc]) {
|
||
$count = 1;
|
||
|
||
// 向正方向延伸
|
||
for ($i = 1; $i <= 4; $i++) {
|
||
$r = $row + $dr * $i;
|
||
$c = $col + $dc * $i;
|
||
if ($r < 0 || $r >= 15 || $c < 0 || $c >= 15) {
|
||
break;
|
||
}
|
||
if (($board[$r][$c] ?? 0) !== $color) {
|
||
break;
|
||
}
|
||
$count++;
|
||
}
|
||
|
||
// 向反方向延伸
|
||
for ($i = 1; $i <= 4; $i++) {
|
||
$r = $row - $dr * $i;
|
||
$c = $col - $dc * $i;
|
||
if ($r < 0 || $r >= 15 || $c < 0 || $c >= 15) {
|
||
break;
|
||
}
|
||
if (($board[$r][$c] ?? 0) !== $color) {
|
||
break;
|
||
}
|
||
$count++;
|
||
}
|
||
|
||
if ($count >= 5) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 判断棋盘是否已下满(平局)。
|
||
*
|
||
* @param array $board 棋盘
|
||
*/
|
||
public static function isBoardFull(array $board): bool
|
||
{
|
||
foreach ($board as $row) {
|
||
foreach ($row as $cell) {
|
||
if ($cell === 0) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
// ─── 状态辅助 ─────────────────────────────────────────────────────
|
||
|
||
/**
|
||
* 判断对局是否属于某个用户。
|
||
*
|
||
* @param int $userId 用户 ID
|
||
*/
|
||
public function belongsToUser(int $userId): bool
|
||
{
|
||
return $this->player_black_id === $userId
|
||
|| $this->player_white_id === $userId;
|
||
}
|
||
|
||
/**
|
||
* 获取指定用户在此对局的棋子颜色。
|
||
* 返回 1(黑棋)或 2(白棋),不在局中返回 null。
|
||
*
|
||
* @param int $userId 用户 ID
|
||
*/
|
||
public function colorOf(int $userId): ?int
|
||
{
|
||
if ($this->player_black_id === $userId) {
|
||
return 1;
|
||
}
|
||
if ($this->player_white_id === $userId) {
|
||
return 2;
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 判断当前是否轮到指定用户行棋(PvP 用)。
|
||
*
|
||
* @param int $userId 用户 ID
|
||
*/
|
||
public function isUserTurn(int $userId): bool
|
||
{
|
||
return $this->colorOf($userId) === $this->current_turn;
|
||
}
|
||
}
|