Ranking::addSolution()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace App\Services;
4
5
use App\Entities\Contest;
6
use App\Entities\Solution;
7
use App\Entities\Team;
8
use App\Entities\User;
9
use App\Repositories\Criteria\WhereIn;
10
use App\Repositories\UserRepository;
11
use Carbon\Carbon;
12
use Illuminate\Database\Eloquent\Collection;
13
14
class Ranking
15
{
16
    /** @var Team[] */
17
    private $teams = [];
18
    private $contest;
19
20
    public function __construct(Contest $contest)
21
    {
22
        $this->contest = $contest;
23
24
        $solutions = $this->getValidSolutions($contest);
25
26
        foreach ($solutions as $solution) {
27
            $this->addSolution($solution);
28
        }
29
    }
30
31
    /**
32
     * 在比赛开始和结束之间的提交才是比赛的合法提交.
33
     *
34
     * @param Contest $contest
35
     *
36
     * @return Collection|Solution[]
37
     */
38
    private function getValidSolutions($contest)
39
    {
40
        $columns = ['created_at', 'order', 'user_id', 'result', 'id'];
41
        $start_at = Carbon::parse($contest->start_time)->subSeconds(1);
42
        $end_at = Carbon::parse($contest->end_time)->addSeconds(1);
43
44
        return $contest->solutions()->whereBetween('created_at', [$start_at, $end_at])->get($columns);
45
    }
46
47
    private function addSolution(Solution $solution)
48
    {
49
        if (! array_key_exists($solution->user_id, $this->teams)) {
50
            $this->teams[$solution->user_id] = new Team($this->contest);
51
        }
52
53
        $this->teams[$solution->user_id]->addSolution($solution);
54
    }
55
56
    /**
57
     * @return Team[]
58
     */
59
    public function result()
60
    {
61
        $this->initTeam();
62
63
        /** @var $result Team[] */
64
        $result = array_values($this->teams);
65
        usort($result, function ($team1, $team2) {
66
            return ! $this->isBetter($team1, $team2);
67
        });
68
69
        return $result;
70
    }
71
72
    private function initTeam()
73
    {
74
        foreach ($this->getTeams() as $user) {
75
            $this->teams[$user->id]->setUser($user);
76
        }
77
    }
78
79
    /**
80
     * @return Collection|User[]
81
     */
82
    protected function getTeams()
83
    {
84
        $repo = app(UserRepository::class);
85
        $whereIn = new WhereIn('id', $this->getTeamsId());
86
        $repo->pushCriteria($whereIn);
87
88
        return $repo->all();
89
    }
90
91
    /**
92
     * @return array
93
     */
94
    private function getTeamsId()
95
    {
96
        return array_keys($this->teams);
97
    }
98
99
    /**
100
     * @param Team $team
101
     * @param Team $current
102
     *
103
     * @return bool
104
     */
105
    private function isBetter($team, $current)
106
    {
107
        // accept more
108
        if ($team->numberOfAccept() > $current->numberOfAccept()) {
109
            return true;
110
        }
111
        // accept equal, but penalty less
112
        if ($team->numberOfAccept() == $current->numberOfAccept()
113
            && $team->totalPenalty() < $current->totalPenalty()) {
114
            return true;
115
        }
116
117
        return false;
118
    }
119
120
    protected function insertElementAtIndex($arr, $ele, $index)
121
    {
122
        $start = array_slice($arr, 0, $index);
123
        $end = array_slice($arr, $index);
124
        $start[] = $ele;
125
126
        return array_merge($start, $end);
127
    }
128
}
129