request = $request; $this->placeRepository = new PlaceRepository(); } public function getInitialData(): IContent { $mapId = (int) $this->request->query('mapId'); $session = $this->request->session(); if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) { return new JsonContent(['error' => 'no_session_found']); } if (!isset($state['currentRound']) || $state['currentRound'] == -1 || $state['currentRound'] >= static::NUMBER_OF_ROUNDS) { $this->startNewGame($state, $mapId); } $response = []; $last = $state['rounds'][$state['currentRound']]; $response['place'] = [ 'panoId' => $last['panoId'], 'pov' => $last['pov']->toArray() ]; $response['history'] = []; for ($i = 0; $i < $state['currentRound']; ++$i) { $round = $state['rounds'][$i]; $response['history'][] = [ 'position' => $round['position']->toArray(), 'guessPosition' => $round['guessPosition']->toArray(), 'distance' => $round['distance'], 'score' => $round['score'] ]; } return new JsonContent($response); } public function evaluateGuess(): IContent { $mapId = (int) $this->request->query('mapId'); $session = $this->request->session(); if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) { return new JsonContent(['error' => 'no_session_found']); } $last = $state['rounds'][$state['currentRound']]; $position = $last['position']; $guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng')); $distance = $this->calculateDistance($position, $guessPosition); $score = $this->calculateScore($distance, $state['area']); $last['guessPosition'] = $guessPosition; $last['distance'] = $distance; $last['score'] = $score; $state['rounds'][$state['currentRound']] = $last; $state['currentRound'] += 1; $response = [ 'result' => [ 'position' => $position->toArray(), 'distance' => $distance, 'score' => $score ] ]; if ($state['currentRound'] < static::NUMBER_OF_ROUNDS) { $next = $state['rounds'][$state['currentRound']]; $response['place'] = [ 'panoId' => $next['panoId'], 'pov' => $next['pov']->toArray() ]; } $session->set('state', $state); return new JsonContent($response); } private function startNewGame(array &$state, int $mapId) { $places = $this->placeRepository->getRandomNForMapWithValidPano($mapId, static::NUMBER_OF_ROUNDS); $state['rounds'] = []; $state['currentRound'] = 0; foreach ($places as $place) { $state['rounds'][] = [ 'placeId' => $place->getId(), 'position' => $place->getPosition(), 'panoId' => $place->getPanoIdCached(), 'pov' => $place->getPov() ]; } $this->request->session()->set('state', $state); } private function calculateDistance(Position $realPosition, Position $guessPosition): float { return $realPosition->calculateDistanceTo($guessPosition); } private function calculateScore(float $distance, float $area): int { $goodness = 1.0 - ($distance / (sqrt($area) * 1000)); return (int) round(pow(static::MAX_SCORE, $goodness)); } }