Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/Actions/Fortify/PasswordValidationRules.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

namespace App\Actions\Fortify;

use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Validation\Rules\Password;

trait PasswordValidationRules
{
/**
* Get the validation rules used to validate passwords.
*
* @return array<int, \Illuminate\Validation\Rules\Password|\Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
* @return array<int, Password|ValidationRule|array<mixed>|string>
*/
protected function passwordRules(): array
{
Expand Down
9 changes: 6 additions & 3 deletions app/Agents/Logic/HeuristicLogic.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace App\Agents\Logic;

use App\Games\Checkers\CheckersLogic;
use App\Games\Hearts\HeartsLogic;
use App\Games\ValidateFour\ValidateFourLogic;
use App\Interfaces\AgentContract;
use App\Models\Games\Game;
use Illuminate\Support\Facades\Log;
Expand Down Expand Up @@ -124,11 +127,11 @@ protected function getGameLogic(Game $game): object

return match ($gameTitle) {
// @phpstan-ignore class.notFound
'checkers' => app(\App\Games\Checkers\CheckersLogic::class),
'checkers' => app(CheckersLogic::class),
// @phpstan-ignore class.notFound
'hearts' => app(\App\Games\Hearts\HeartsLogic::class),
'hearts' => app(HeartsLogic::class),
// @phpstan-ignore class.notFound, match.alwaysFalse
'validatefour' => app(\App\Games\ValidateFour\ValidateFourLogic::class),
'validatefour' => app(ValidateFourLogic::class),
default => throw new \Exception("Unsupported game type: {$gameTitle}"),
};
}
Expand Down
9 changes: 6 additions & 3 deletions app/Agents/Logic/MinimaxLogic.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace App\Agents\Logic;

use App\Games\Checkers\CheckersLogic;
use App\Games\Hearts\HeartsLogic;
use App\Games\ValidateFour\ValidateFourLogic;
use App\Interfaces\AgentContract;
use App\Models\Games\Game;
use Illuminate\Support\Facades\Log;
Expand Down Expand Up @@ -163,11 +166,11 @@ protected function getGameLogic(Game $game): object

return match ($gameTitle) {
// @phpstan-ignore class.notFound
'checkers' => app(\App\Games\Checkers\CheckersLogic::class),
'checkers' => app(CheckersLogic::class),
// @phpstan-ignore class.notFound
'hearts' => app(\App\Games\Hearts\HeartsLogic::class),
'hearts' => app(HeartsLogic::class),
// @phpstan-ignore class.notFound, match.alwaysFalse
'validatefour' => app(\App\Games\ValidateFour\ValidateFourLogic::class),
'validatefour' => app(ValidateFourLogic::class),
default => throw new \Exception("Unsupported game type: {$gameTitle}"),
};
}
Expand Down
9 changes: 6 additions & 3 deletions app/Agents/Logic/RandomLogic.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace App\Agents\Logic;

use App\Games\Checkers\CheckersLogic;
use App\Games\Hearts\HeartsLogic;
use App\Games\ValidateFour\ValidateFourLogic;
use App\Interfaces\AgentContract;
use App\Models\Games\Game;
use Illuminate\Support\Facades\Log;
Expand Down Expand Up @@ -65,11 +68,11 @@ protected function getGameLogic(Game $game): object

return match ($gameTitle) {
// @phpstan-ignore class.notFound
'checkers' => app(\App\Games\Checkers\CheckersLogic::class),
'checkers' => app(CheckersLogic::class),
// @phpstan-ignore class.notFound
'hearts' => app(\App\Games\Hearts\HeartsLogic::class),
'hearts' => app(HeartsLogic::class),
// @phpstan-ignore class.notFound, match.alwaysFalse
'validatefour' => app(\App\Games\ValidateFour\ValidateFourLogic::class),
'validatefour' => app(ValidateFourLogic::class),
default => throw new \Exception("Unsupported game type: {$gameTitle}"),
};
}
Expand Down
7 changes: 6 additions & 1 deletion app/GameEngine/GameEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ public function processPlayerAction(
$game,
$action,
$mode,
$gameState
$gameState,
$player
);

// Record the successful action
Expand All @@ -155,6 +156,10 @@ public function processPlayerAction(
$gameState = $coordinationResult->updatedGameState;
$game->game_state = $gameState->toArray();
$game->save();

// Mark the current action as completed
$actionRecord->coordination_completed_at = now();
$actionRecord->save();
}

// ── 5. GAME LIFECYCLE PROGRESSION ───────────────────────────
Expand Down
3 changes: 2 additions & 1 deletion app/GameEngine/Interfaces/GameTitleContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use App\Exceptions\Game\TurnTimerExpiredException;
use App\GameEngine\GameOutcome;
use App\GameEngine\ValidationResult;
use App\Games\ValidateFour\BaseValidateFourMode;
use App\Models\Auth\User;
use App\Models\Games\Game;
use Carbon\Carbon;
Expand Down Expand Up @@ -55,7 +56,7 @@
* }
* ```
*
* @see \App\Games\ValidateFour\BaseValidateFourMode For Connect Four implementation
* @see BaseValidateFourMode For Connect Four implementation
*/
interface GameTitleContract
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
namespace App\GameEngine\Lifecycle\Progression;

use App\DataTransferObjects\Games\CoordinatedActionResult;
use App\Enums\ActionType;
use App\GameEngine\Interfaces\GameActionContract;
use App\Models\Games\Action;
use App\Models\Games\Game;
use App\Models\Games\Player;

/**
* Handles coordinated actions where multiple players must submit actions
Expand All @@ -22,9 +24,10 @@ class CoordinatedActionProcessor
* @param GameActionContract $action The action being processed
* @param mixed $mode The game mode handler
* @param object $gameState The current game state
* @param Player $player The current player
* @return CoordinatedActionResult Result indicating if coordination is needed and status
*/
public function process(Game $game, GameActionContract $action, mixed $mode, object $gameState): CoordinatedActionResult
public function process(Game $game, GameActionContract $action, mixed $mode, object $gameState, Player $player): CoordinatedActionResult
{
// Check if this action requires coordination
if (! $this->isCoordinatedAction($action)) {
Expand All @@ -35,11 +38,19 @@ public function process(Game $game, GameActionContract $action, mixed $mode, obj
$coordinationSequence = $this->getSequenceNumber($game, $coordinationGroup);
$requiredCount = $this->getRequiredPlayerCount($game, $action, $gameState);

// Check if coordination is complete
// Check if coordination is complete (counting existing actions + current action)
$completedCount = $this->getCompletedCount($game, $coordinationGroup);

if ($completedCount >= $requiredCount) {
return $this->completeCoordination($game, $mode, $gameState, $coordinationGroup, $coordinationSequence);
if ($completedCount + 1 >= $requiredCount) {
return $this->completeCoordination(
$game,
$mode,
$gameState,
$coordinationGroup,
$coordinationSequence,
$action,
$player
);
}

return CoordinatedActionResult::coordinated(
Expand Down Expand Up @@ -123,24 +134,38 @@ protected function completeCoordination(
mixed $mode,
object $gameState,
string $coordinationGroup,
int $coordinationSequence
int $coordinationSequence,
GameActionContract $action,
Player $player
): CoordinatedActionResult {
// Retrieve all coordinated actions
// Retrieve all previously coordinated actions
$coordinatedActions = Action::where('game_id', $game->id)
->withCoordinationGroup($coordinationGroup)
->pendingCoordination()
->with('player')
->get();

// Process the coordinated action through the game mode
// Add the current action to the list (as a transient Action model)
$currentActionModel = new Action;
// Since we can't easily hydrate it completely without saving, we'll set what's needed for coordination
$currentActionModel->setRelation('player', $player);
$currentActionModel->action_details = $action->toArray();
$currentActionModel->action_type = ActionType::from($action->getType());

$coordinatedActions->push($currentActionModel);

// Process the coordinated actions through the game mode
$updatedGameState = $this->processCoordinatedActions($mode, $gameState, $coordinatedActions);

// Mark all actions as completed
// Mark all existing actions as completed
Action::where('game_id', $game->id)
->withCoordinationGroup($coordinationGroup)
->pendingCoordination()
->update(['coordination_completed_at' => now()]);

// Note: The current action is not yet in the DB, so it won't be updated here.
// The calling component is responsible for saving the current action with proper status.

return CoordinatedActionResult::coordinated(
coordinationGroup: $coordinationGroup,
coordinationSequence: $coordinationSequence,
Expand Down
15 changes: 10 additions & 5 deletions app/GameEngine/ModeRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

use App\Exceptions\GameModeNotFoundException;
use App\GameTitles\BaseGameTitle;
use App\GameTitles\Checkers\Modes\StandardMode;
use App\GameTitles\ConnectFour\Modes\EightBySevenMode;
use App\GameTitles\ConnectFour\Modes\FiveMode;
use App\GameTitles\ConnectFour\Modes\NineBySixMode;
use App\GameTitles\ConnectFour\Modes\PopOutMode;
use App\Models\Games\Game;

/**
Expand All @@ -22,17 +27,17 @@ class ModeRegistry
*/
private array $modes = [
'checkers' => [
'standard' => \App\GameTitles\Checkers\Modes\StandardMode::class,
'standard' => StandardMode::class,
],
'hearts' => [
'standard' => \App\GameTitles\Hearts\Modes\StandardMode::class,
],
'connect-four' => [
'standard' => \App\GameTitles\ConnectFour\Modes\StandardMode::class,
'pop-out' => \App\GameTitles\ConnectFour\Modes\PopOutMode::class,
'five' => \App\GameTitles\ConnectFour\Modes\FiveMode::class,
'eight-by-seven' => \App\GameTitles\ConnectFour\Modes\EightBySevenMode::class,
'nine-by-six' => \App\GameTitles\ConnectFour\Modes\NineBySixMode::class,
'pop-out' => PopOutMode::class,
'five' => FiveMode::class,
'eight-by-seven' => EightBySevenMode::class,
'nine-by-six' => NineBySixMode::class,
],
];

Expand Down
3 changes: 2 additions & 1 deletion app/GameTitles/ConnectFour/ConnectFourBoard.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Enums\GamePhase;
use App\Enums\GameStatus;
use App\GameTitles\BaseGameState;
use App\Interfaces\GameTitleContract;

/**
* Immutable game state for Connect Four (Connect Four variant).
Expand Down Expand Up @@ -59,7 +60,7 @@
* $gameState = ConnectFourConnectFourBoard::fromArray($game->game_state);
* ```
*
* @see \App\Interfaces\GameTitleContract For the interface all game modes must implement
* @see GameTitleContract For the interface all game modes must implement
*/
final class ConnectFourBoard extends BaseGameState
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Http\Resources\Account\ProgressionResource;
use App\Http\Traits\ApiResponses;
use App\Models\Gamification\UserTitleLevel;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

Expand All @@ -27,7 +28,7 @@ public function __invoke(Request $request): JsonResponse
{
$user = $request->user();

/** @var \Illuminate\Database\Eloquent\Collection<int, UserTitleLevel> $levelCollection */
/** @var Collection<int, UserTitleLevel> $levelCollection */
$levelCollection = $user->titleLevels()
->orderByDesc('last_played_at')
->get();
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/Api/V1/Auth/RegisterController.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function __invoke(RegisterRequest $request): JsonResponse

return response()->json([
'message' => 'Registration successful. Please check your email to verify your account.',
'registration_id' => $registration->id,
'registration_id' => $registration->uuid,
], 201);
}
}
8 changes: 5 additions & 3 deletions app/Http/Controllers/Api/V1/Auth/SocialAuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use App\Services\Auth\AuthService;
use Illuminate\Http\JsonResponse;
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\AbstractProvider;

class SocialAuthController extends Controller
{
Expand All @@ -24,9 +25,10 @@ public function __invoke(SocialLoginRequest $request): JsonResponse
{
try {
// Verify token with provider
/** @phpstan-ignore-next-line */
$providerUser = Socialite::driver($request->provider)
->userFromToken($request->access_token);
$driver = Socialite::driver($request->provider);

/** @var AbstractProvider $driver */
$providerUser = $driver->userFromToken($request->access_token);

// Find or create user and social account
$result = $this->authService->handleSocialLogin(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Http\Traits\ApiResponses;
use App\Models\Auth\User;
use App\Models\Competitions\Tournament;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

Expand All @@ -21,7 +22,7 @@ public function show(Request $request, Tournament $tournament): JsonResponse
{
$tournament->load(['users.avatar.image']);

/** @var \Illuminate\Database\Eloquent\Collection<int, User> $users */
/** @var Collection<int, User> $users */
$users = $tournament->users()
->orderBy('tournament_user.placement', 'asc')
->orderBy('tournament_user.earnings', 'desc')
Expand Down
3 changes: 2 additions & 1 deletion app/Http/Controllers/Api/V1/System/ConfigController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Http\Controllers\Api\V1\System;

use App\Enums\GameTitle;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;

Expand All @@ -24,7 +25,7 @@ public function __invoke(): JsonResponse
'leaderboards' => true,
'sse_feeds' => true,
],
'supported_games' => collect(\App\Enums\GameTitle::cases())->map(fn ($title) => [
'supported_games' => collect(GameTitle::cases())->map(fn ($title) => [
'key' => $title->value,
'name' => $title->label(),
'min_players' => $title->minPlayers(),
Expand Down
3 changes: 2 additions & 1 deletion app/Http/Controllers/Api/V1/System/FeedbackController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
use App\Http\Controllers\Controller;
use App\Http\Resources\System\FeedbackResource;
use App\Models\System\Feedback;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Enum;

class FeedbackController extends Controller
{
/**
* @return \Illuminate\Http\JsonResponse
* @return JsonResponse
*/
public function __invoke(Request $request)
{
Expand Down
Loading
Loading