diff --git a/api/app/Http/Controllers/GameController.php b/api/app/Http/Controllers/GameController.php index e731b2a..d798c24 100644 --- a/api/app/Http/Controllers/GameController.php +++ b/api/app/Http/Controllers/GameController.php @@ -6,6 +6,7 @@ use App\Models\Game; use Illuminate\Http\Request; use App\Http\Requests\StoreGameRequest; use Illuminate\Support\Facades\Auth; +use App\Models\MatchGame; class GameController extends Controller { @@ -34,15 +35,18 @@ class GameController extends Controller $user = Auth::user(); - $activeGame = Game::where(function ($query) use ($user) { - $query->where('player1_user_id', $user->id) - ->orWhere('player2_user_id', $user->id); - }) - ->whereIn('status', ['Pending', 'Playing']) - ->exists(); + $activeMatch = MatchGame::where(function ($q) use ($user) { + $q->where('player1_user_id', $user->id) + ->orWhere('player2_user_id', $user->id); + })->whereIn('status', ['Pending', 'Playing'])->exists(); - if ($activeGame) { - return response()->json(['message' => 'You already have an active game.'], 400); + $activeGame = Game::where(function ($q) use ($user) { + $q->where('player1_user_id', $user->id) + ->orWhere('player2_user_id', $user->id); + })->whereIn('status', ['Pending', 'Playing'])->exists(); + + if ($activeMatch || $activeGame) { + return response()->json(['message' => 'You already have an active game or match.'], 400); } $game = Game::create([ diff --git a/api/app/Http/Controllers/MatchController.php b/api/app/Http/Controllers/MatchController.php new file mode 100644 index 0000000..09f5c39 --- /dev/null +++ b/api/app/Http/Controllers/MatchController.php @@ -0,0 +1,134 @@ +with(['winner', 'player1', 'player2']); + + if ($request->has('type')) { + $query->where('type', $request->type); + } + + if ($request->has('status')) { + $query->where('status', $request->status); + } + + $query->orderBy('began_at', 'desc'); + + return response()->json($query->paginate(15)); + } + + public function store(StoreMatchRequest $request) + { + $validated = $request->validated(); + $user = Auth::user(); + + $activeMatch = MatchGame::where(function ($q) use ($user) { + $q->where('player1_user_id', $user->id) + ->orWhere('player2_user_id', $user->id); + })->whereIn('status', ['Pending', 'Playing'])->exists(); + + $activeGame = Game::where(function ($q) use ($user) { + $q->where('player1_user_id', $user->id) + ->orWhere('player2_user_id', $user->id); + })->whereIn('status', ['Pending', 'Playing'])->exists(); + + if ($activeMatch || $activeGame) { + return response()->json(['message' => 'You already have an active game or match.'], 400); + } + + $match = MatchGame::create([ + 'type' => $validated['type'], + 'status' => 'Pending', + 'player1_user_id' => $user->id, + 'player2_user_id' => $user->id, + 'winner_user_id' => $user->id, + 'loser_user_id' => $user->id, + 'stake' => $validated['stake'], + 'began_at' => now(), + 'player1_marks' => 0, + 'player2_marks' => 0, + 'player1_points' => 0, + 'player2_points' => 0, + 'custom' => null + ]); + + return response()->json([ + 'message' => 'Match created successfully', + 'match' => $match + ], 201); + } + + public function show(MatchGame $match) + { + $match->load(['player1', 'player2', 'winner']); + return response()->json($match); + } + + public function join(MatchGame $match) + { + $user = Auth::user(); + + if ($match->player1_user_id == $user->id) { + return response()->json(['message' => 'Waiting for opponent...', 'match' => $match]); + } + + if ($match->status !== 'Pending') { + return response()->json(['message' => 'Match is full or started'], 400); + } + + $activeMatch = MatchGame::where(function ($q) use ($user) { + $q->where('player1_user_id', $user->id) + ->orWhere('player2_user_id', $user->id); + })->whereIn('status', ['Pending', 'Playing'])->exists(); + + if ($activeMatch) { + return response()->json(['message' => 'You are already in another active match.'], 400); + } + + $match->update([ + 'status' => 'Playing', + 'player2_user_id' => $user->id + ]); + + return response()->json([ + 'message' => 'Joined match successfully!', + 'match' => $match + ]); + } + + public function update(Request $request, MatchGame $match) + { + if ($match->status == 'Ended') { + return response()->json(['message' => 'Match already ended'], 400); + } + + $data = $request->validate([ + 'status' => 'in:Playing,Ended,Interrupted', + 'winner_user_id' => 'exists:users,id', + 'loser_user_id' => 'exists:users,id', + 'player1_marks' => 'integer', + 'player2_marks' => 'integer', + 'player1_points' => 'integer', + 'player2_points' => 'integer', + 'total_time' => 'numeric' + ]); + + if (isset($data['status']) && $data['status'] === 'Ended') { + $data['ended_at'] = now(); + } + + $match->update($data); + + return response()->json($match); + } +} \ No newline at end of file diff --git a/api/app/Http/Requests/StoreMatchRequest.php b/api/app/Http/Requests/StoreMatchRequest.php new file mode 100644 index 0000000..b07170d --- /dev/null +++ b/api/app/Http/Requests/StoreMatchRequest.php @@ -0,0 +1,22 @@ + 'required|in:3,9', + 'stake' => 'required|integer|min:1', + ]; + } +} \ No newline at end of file diff --git a/api/app/Models/MatchGame.php b/api/app/Models/MatchGame.php new file mode 100644 index 0000000..5e6a56e --- /dev/null +++ b/api/app/Models/MatchGame.php @@ -0,0 +1,58 @@ + 'datetime', + 'ended_at' => 'datetime', + 'player1_marks' => 'integer', + 'player2_marks' => 'integer', + 'player1_points' => 'integer', + 'player2_points' => 'integer', + 'stake' => 'integer', + ]; + + public function player1() + { + return $this->belongsTo(User::class, 'player1_user_id'); + } + + public function player2() + { + return $this->belongsTo(User::class, 'player2_user_id'); + } + + public function winner() + { + return $this->belongsTo(User::class, 'winner_user_id'); + } +} \ No newline at end of file diff --git a/api/routes/api.php b/api/routes/api.php index 2b9fdcd..d0f9b55 100644 --- a/api/routes/api.php +++ b/api/routes/api.php @@ -3,6 +3,7 @@ use App\Http\Controllers\AuthController; use App\Http\Controllers\GameController; use App\Http\Controllers\UserController; +use App\Http\Controllers\MatchController; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; @@ -26,4 +27,12 @@ Route::middleware('auth:sanctum')->group(function () { Route::post('/games/{game}/resign', [GameController::class, 'resign']); Route::get('/users/{user}/matches', [UserController::class, 'getMatches']); Route::post('games/{game}/join', [GameController::class, 'join']); +}); + +Route::middleware('auth:sanctum')->group(function () { + Route::get('matches', [MatchController::class, 'index']); + Route::post('matches', [MatchController::class, 'store']); + Route::get('matches/{match}', [MatchController::class, 'show']); + Route::post('matches/{match}/join', [MatchController::class, 'join']); + Route::put('matches/{match}', [MatchController::class, 'update']); }); \ No newline at end of file