/**
  * Insertion test
  *
  * @return void
  */
 public function testInsert()
 {
     $user1 = factory(App\Models\User::class)->create();
     $user2 = factory(App\Models\User::class)->create();
     $battleRequest = new BattleRequest();
     $battleRequest->challenger_id = $user1->id;
     $battleRequest->challenged_id = $user2->id;
     $battleRequest->save();
     // is request in database?
     $this->seeInDatabase('battle_requests', ['challenger_id' => $user1->id, 'challenged_id' => $user2->id]);
     // can challenger and challenged user be retrieved?
     $this->assertNotNull($battleRequest->challenger()->get()->values()->keyBy('id')->get($user1->id));
     $this->assertNotNull($battleRequest->challenged()->get()->values()->keyBy('id')->get($user2->id));
     // can users retrieve their open battles?
     $this->assertNotNull($user1->BattleRequestsChallenger()->get()->values()->keyBy('id')->get($battleRequest->id));
     $this->assertNotNull($user2->BattleRequestsChallenged()->get()->values()->keyBy('id')->get($battleRequest->id));
 }
 /**
  * Find a random opponent for the authenticated user based on rating.
  *
  * @return \Illuminate\Http\JsonResponse
  */
 public function getRandomOpponent()
 {
     $user = Auth::user();
     if (is_null($user)) {
         return response('Unauthorized', 401);
     }
     // Number of possible opponents = Number of rappers - 1 (Authenticated user)
     //     - Number of open battles of authenticated user
     //     - Number of battle requests of authenticated user
     $possibleOpponentCount = User::rapper()->count() - 1 - $user->openBattles()->count() - $user->battleRequests()->count();
     $opponent = null;
     // This is faster because there are no unecessary iterations.
     if ($possibleOpponentCount == 1) {
         // There is only one possible opponent.
         $opponent = User::validOpponentFor($user)->first();
     } elseif ($possibleOpponentCount > 1) {
         // Increase the search range exponentially to make sure an opponent is found.
         $exponentialBase = 2;
         $rating = $user->rating;
         $validOpponents = User::validOpponentFor($user);
         $validOpponentsCnt = $validOpponents->count();
         if (!$validOpponents->get()->isEmpty()) {
             for ($i = 0; is_null($opponent); $i++) {
                 $range = pow($exponentialBase, $i);
                 $minRating = $rating - $range;
                 $maxRating = $rating + $range;
                 $possibleOpponents = $validOpponents->ratedBetween($minRating, $maxRating)->get();
                 if (!$possibleOpponents->isEmpty()) {
                     $opponent = $possibleOpponents->random();
                     // Log for later optimizing
                     Log::info('Random opponent found.', ['possible opponents' => $possibleOpponentCount, 'exponential base' => $exponentialBase, 'iterations' => $i]);
                 }
             }
         }
     }
     if (!is_null($opponent)) {
         $battleRequest = new BattleRequest();
         $battleRequest->challenger()->associate($user);
         $battleRequest->challenged()->associate($opponent);
         $battleRequest->save();
         $opponent = $opponent->profilePreview();
     }
     return response()->json(['opponent' => $opponent]);
 }