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