Completed
Push — master ( cbe770...a806e4 )
by he
05:56
created

Ranking::getValidSolutions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
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
    private function addSolution(Solution $solution)
32
    {
33
        if (!array_key_exists($solution->user_id, $this->teams)) {
34
            $this->teams[$solution->user_id] = new Team($this->contest);
35
        }
36
37
        $this->teams[$solution->user_id]->addSolution($solution);
38
    }
39
40
    /**
41
     * @return Team[]
42
     */
43
    public function result()
44
    {
45
        /** @var $result Team[] */
46
        $result = [];
47
48
        $this->initTeam();
49
50
        foreach ($this->teams as $team) {
51
            $inserted = false;
52
            $totalSolutions = count($result);
53
            for ($i = 0; $i < $totalSolutions; $i++) {
54
                if ($this->isBetter($team, $result[$i])) {
55
                    $result = $this->insertElementAtIndex($result, $team, $i);
56
                    $inserted = true;
57
                }
58
            }
59
            if (!$inserted) {
60
                $result[] = $team;
61
            }
62
        }
63
64
        return $result;
65
    }
66
67
    /**
68
     * @param Team $team
69
     * @param Team $current
70
     *
71
     * @return bool
72
     */
73
    private function isBetter($team, $current)
74
    {
75
        // accept more
76
        if ($team->numberOfAccept() > $current->numberOfAccept()) {
77
            return true;
78
        }
79
        // accept equal, but penalty less
80
        if ($team->numberOfAccept() == $current->numberOfAccept()
81
            && $team->totalPenalty() < $current->totalPenalty()) {
82
            return true;
83
        }
84
85
        return false;
86
    }
87
88
    /**
89
     * @return Collection|User[]
90
     */
91
    protected function getTeams()
92
    {
93
        $repo = app(UserRepository::class);
94
        $whereIn = new WhereIn('id', $this->getTeamsId());
95
        $repo->pushCriteria($whereIn);
96
97
        return $repo->all();
98
    }
99
100
    /**
101
     * @return array
102
     */
103
    private function getTeamsId()
104
    {
105
        return array_keys($this->teams);
106
    }
107
108
    protected function insertElementAtIndex($arr, $ele, $index)
109
    {
110
        $start = array_slice($arr, 0, $index);
111
        $end = array_slice($arr, $index);
112
        $start[] = $ele;
113
114
        return array_merge($start, $end);
115
    }
116
117
    /**
118
     * 在比赛开始和结束之间的提交才是比赛的合法提交.
119
     *
120
     * @param Contest $contest
121
     *
122
     * @return Collection|Solution[]
123
     */
124
    private function getValidSolutions($contest)
125
    {
126
        $columns = ['created_at', 'order', 'user_id', 'result', 'id'];
127
        $start_at = Carbon::parse($contest->start_time)->subSeconds(1);
128
        $end_at = Carbon::parse($contest->end_time)->addSeconds(1);
129
130
        return $contest->solutions()->whereBetween('created_at', [$start_at, $end_at])->get($columns);
131
    }
132
133
    private function initTeam()
134
    {
135
        foreach ($this->getTeams() as $user) {
136
            $this->teams[$user->id]->setUser($user);
137
        }
138
    }
139
}
140