Files
chatroom/app/Models/GomokuGame.php

225 lines
5.8 KiB
PHP
Raw Normal View History

<?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;
}
}