]> git.localhorst.tv Git - alttp.git/blob - app/Models/Channel.php
fix scoring
[alttp.git] / app / Models / Channel.php
1 <?php
2
3 namespace App\Models;
4
5 use Illuminate\Broadcasting\PrivateChannel;
6 use Illuminate\Database\Eloquent\BroadcastsEvents;
7 use Illuminate\Database\Eloquent\Factories\HasFactory;
8 use Illuminate\Database\Eloquent\Model;
9 use Illuminate\Support\Arr;
10
11 class Channel extends Model {
12
13         use BroadcastsEvents;
14         use HasFactory;
15
16         public function broadcastOn($event) {
17                 $channels = [
18                         new PrivateChannel('Channel.'.$this->id),
19                 ];
20                 return $channels;
21         }
22
23         public function getCurrentEpisode() {
24                 return $this->episodes()
25                         ->where('start', '<', now()->subMinutes(10))
26                         ->orderBy('start', 'DESC')
27                         ->first();
28         }
29
30         public function getGuessingLeaderboard() {
31                 return $this->winners()->selectRaw('(select t2.uname from guessing_winners t2 where t2.uid = guessing_winners.uid order by created_at desc limit 1) as name, sum(score) as score')->groupBy('uid')->orderBy('score', 'desc')->limit(10)->get();
32         }
33
34         public function hasActiveGuessing() {
35                 return !is_null($this->guessing_start);
36         }
37
38         public function isAcceptingGuesses() {
39                 return !is_null($this->guessing_start) && is_null($this->guessing_end);
40         }
41
42         public function startGuessing($type) {
43                 $this->guessing_type = $type;
44                 $this->guessing_start = now();
45                 $this->save();
46         }
47
48         public function stopGuessing() {
49                 $this->guessing_end = now();
50                 $this->save();
51         }
52
53         public function getGuessingSetting($name, $default = null) {
54                 if (empty($this->guessing_settings) ||
55                         empty($this->guessing_type) ||
56                         !array_key_exists($this->guessing_type, $this->guessing_settings) ||
57                         !array_key_exists($name, $this->guessing_settings[$this->guessing_type])
58                 ) {
59                         return $default;
60                 }
61                 return $this->guessing_settings[$this->guessing_type][$name];
62         }
63
64         public function solveGuessing($solution) {
65                 $start = $this->guessing_start;
66                 $end = is_null($this->guessing_end) ? now() : $this->guessing_end;
67                 $guesses = $this->guesses()->whereBetween('created_at', [$start, $end])->orderBy('created_at', 'ASC')->get();
68                 $unique_guesses = [];
69                 foreach ($guesses as $guess) {
70                         $unique_guesses[$guess->uid] = $guess;
71                 }
72                 $candidates = [];
73                 foreach ($unique_guesses as $guess) {
74                         if ($guess->guess == $solution) {
75                                 $candidates[] = $guess;
76                         }
77                 }
78                 if (empty($candidates) && is_numeric($solution)) {
79                         $min_distance = null;
80                         foreach ($unique_guesses as $guess) {
81                                 $distance = abs(intval($guess->guess) - intval($solution));
82                                 if (is_null($min_distance) || $distance == $min_distance) {
83                                         $candidates[] = $guess;
84                                         if (is_null($min_distance)) {
85                                                 $min_distance = $distance;
86                                         }
87                                 } else if ($distance < $min_distance) {
88                                         $candidates = [$guess];
89                                         $min_distance = $distance;
90                                 }
91                         }
92                 }
93                 $winners = [];
94                 $first = true;
95                 foreach ($candidates as $candidate) {
96                         $score = $this->scoreGuessing($solution, $candidate->guess, $first);
97                         $winner = new GuessingWinner();
98                         $winner->channel()->associate($this);
99                         $winner->pod = $start;
100                         $winner->uid = $candidate->uid;
101                         $winner->uname = $candidate->uname;
102                         $winner->guess = $candidate->guess;
103                         $winner->solution = $solution;
104                         $winner->score = $score;
105                         $winner->save();
106                         $winners[] = $winner;
107                         $first = false;
108                 }
109                 return $winners;
110         }
111
112         public function clearGuessing() {
113                 $this->guessing_start = null;
114                 $this->guessing_end = null;
115                 $this->save();
116         }
117
118         public function registerGuess($uid, $uname, $guess) {
119                 $model = new GuessingGuess();
120                 $model->channel()->associate($this);
121                 $model->uid = $uid;
122                 $model->uname = $uname;
123                 $model->guess = $guess;
124                 $model->save();
125         }
126
127         public function scoreGuessing($solution, $guess, $first) {
128                 if ($guess == $solution) {
129                         if ($first) {
130                                 return $this->getGuessingSetting('points_exact_first', 1);
131                         }
132                         return $this->getGuessingSetting('points_exact_other', 1);
133                 }
134                 $distance = abs(intval($guess) - intval($solution));
135                 if ($distance <= $this->getGuessingSetting('points_close_max', 3)) {
136                         if ($first) {
137                                 return $this->getGuessingSetting('points_close_first', 1);
138                         }
139                         return $this->getGuessingSetting('points_close_other', 1);
140                 }
141                 return 0;
142         }
143
144         public function isValidGuess($solution) {
145                 if ($this->guessing_type == 'gtbk') {
146                         $int_solution = intval($solution);
147                         return $int_solution > 0 && $int_solution < 23;
148                 }
149                 return false;
150         }
151
152         public function listAnd($entries) {
153                 $lang = empty($this->languages) ? 'en' : $this->languages[0];
154                 if ($lang == 'de') {
155                         return Arr::join($entries, ', ', ' und ');
156                 }
157                 return Arr::join($entries, ', ', ' and ');
158         }
159
160         public function crews() {
161                 return $this->hasMany(ChannelCrew::class);
162         }
163
164         public function episodes() {
165                 return $this->belongsToMany(Episode::class)
166                         ->using(Restream::class)
167                         ->withPivot('accept_comms', 'accept_tracker');
168         }
169
170         public function guesses() {
171                 return $this->hasMany(GuessingGuess::class);
172         }
173
174         public function organization() {
175                 return $this->belongsTo(Organization::class);
176         }
177
178         public function winners() {
179                 return $this->hasMany(GuessingWinner::class);
180         }
181
182         protected $casts = [
183                 'chat' => 'boolean',
184                 'chat_commands' => 'array',
185                 'chat_settings' => 'array',
186                 'guessing_settings' => 'array',
187                 'guessing_start' => 'datetime',
188                 'guessing_end' => 'datetime',
189                 'languages' => 'array',
190                 'join' => 'boolean',
191         ];
192
193         protected $hidden = [
194                 'created_at',
195                 'ext_id',
196                 'updated_at',
197         ];
198
199 }