activeBoxes = $this->boxNames(); $this->lineUpMap = $this->lineUpMap(); $this->player_on_field_counter = 0; for ($i = 1; $i <= 35; $i++) { $this->boxes[$i] = []; if (isset($this->activeBoxes[$i])) { $this->beschriftung[$i] = $this->activeBoxes[$i]; } else { $this->beschriftung[$i] = ''; } } $this->lineup = $this->lineUpMap[$this->activeLineUp]; } #[On('match-update')] public function matchUpdate(int $match_id) { $this->match_id = $match_id; } #[On('team-update')] public function syncData(int $team_id) { $this->players = PlayerCalculator::load($team_id); $this->team_name = SofaScoreRosa::where('ss_team_id', $team_id)->value('ss_team_name'); $this->team_id = $team_id; $this->loadPlacement(); } #[On('lineup-update')] public function lineUpUpdate(int|string $activeLineUp) { $this->activeLineUp = $activeLineUp; $this->lineup = $this->lineUpMap[$activeLineUp]; $this->loadPlacement(); } #[On('element-dropped-in-box')] public function handleElementDropped(mixed $elementData, mixed $boxNumber): void { $boxNumber = (int) $boxNumber; $player = is_array($elementData) ? $elementData : json_decode($elementData, true); if (! $player || ! isset($player['id'])) { return; } // when drag from field to field remove from prviouse field to prevent doubles foreach ($this->boxes as $k => $record) { if (count($record) && $record['id'] == (int) $player['id']) { $this->clearBox($k); } } // when drag from source remove from proviuse field foreach ($this->players as $k => $record) { if ($record['id'] == (int) $player['id']) { if ($this->boxes[$boxNumber]) { $this->clearBox($boxNumber); } $this->boxes[$boxNumber] = $record; $this->players[$k]['active'] = 1; $this->players[$k]['pos'] = $this->activeBoxes[$boxNumber]; $this->player_on_field_counter++; } } $this->storePlacement(); if ($this->player_on_field_counter >= 10) { $this->calculateAspg(); } else { $this->dispatch('update-players', players: $this->players); } } public function loadPlacement() { $this->clearResultTable(); if ($this->team_id) { $this->player_on_field_counter = 0; $res = SsLineupMemory::where('client_id', Auth::user()->client_id)->where('team_id', $this->team_id)->where('lineup', $this->activeLineUp)->first(); if ($res) { // Log::debug('SsLineupMemory', $res->toArray()); $placement = json_decode($res->placement, 1); foreach ($this->players as $k => $record) { // dd($this->lineup, $record, $stored_positions); $id = $record['id']; if (isset($placement[$id]) && in_array($placement[$id], $this->lineup)) { $this->boxes[$placement[$id]] = $record; $this->players[$k]['active'] = 1; $this->players[$k]['pos'] = $record['pos_ori']; $this->player_on_field_counter++; } } } } $this->dispatch('update-players', players: $this->players); } public function storePlacement() { $store = []; foreach ($this->boxes as $pos => $value) { if ($value) { $store[$value['id']] = $pos; } } SsLineupMemory::updateOrCreate([ 'client_id' => Auth::user()->client_id, 'team_id' => $this->team_id, 'lineup' => $this->activeLineUp, ], [ 'placement' => json_encode($store), 'team_name' => $this->team_name, ]); } public function updateLineup(?string $state) { $this->clearResultTable(); if (isset($this->lineupsMap[$state])) { $this->lineup = $this->lineupsMap[$state]; } else { $this->lineup = []; } } public function clearBox(int $boxNumber): void { if (isset($this->boxes[$boxNumber])) { $tmp = $this->boxes[$boxNumber]; $player_id = 0; foreach ($tmp as $key => $value) { if ($key == 'id') { $player_id = $value; } } foreach ($this->players as $k => $record) { if ($record['id'] == (int) $player_id) { $this->boxes[$boxNumber] = []; $this->players[$k]['pos'] = ''; $this->players[$k]['active'] = 0; $this->player_on_field_counter--; } } foreach ($this->players as $k => $record) { $this->players[$k]['gls'] = ''; $this->players[$k]['fls'] = ''; $this->players[$k]['ofs'] = ''; $this->players[$k]['snt'] = ''; $this->players[$k]['tsh'] = ''; $this->players[$k]['crd'] = ''; } $this->storePlacement(); $this->loadPlacement(); } } public function clearResultTable(): void { for ($i = 1; $i <= 35; $i++) { $this->boxes[$i] = []; } foreach ($this->players as $k => $record) { $this->players[$k]['active'] = 0; $this->players[$k]['gls'] = ''; $this->players[$k]['fls'] = ''; $this->players[$k]['ofs'] = ''; $this->players[$k]['snt'] = ''; $this->players[$k]['tsh'] = ''; $this->players[$k]['crd'] = ''; } $this->player_on_field_counter = 0; $this->dispatch('update-players', players: $this->players); } public function copyDevelopment() { if ($this->player_on_field_counter < 10) { Notification::make()->title('Needs a calculation first ') ->info() ->send(); return; } $copystring = ''; foreach ($this->calculationVariables as $row) { if ($copystring == '') { $keys = array_keys($row); $copystring .= implode(';', $keys)."\n"; } $copystring .= implode(';', $row)."\n"; } $this->js("navigator.clipboard.writeText(`$copystring`)"); Notification::make() ->title('Calculation variables copied') ->success() ->send(); } public function copyResult() { if ($this->player_on_field_counter < 10) { Notification::make()->title('Needs a calculation first ') ->info() ->send(); return; } $header = ['name', 'foot', 'events', 'average min', 'position', 'on field', 'gls', 'fls', 'ofs', 'snt', 'tsh', 'crd']; $copystring = implode(';', $header)."\n"; foreach ($this->players as $row) { $tmp = []; $tmp[] = $row['name']; $tmp[] = $row['foot']; $tmp[] = $row['tot_evt']; $tmp[] = $row['ave_min']; if ($row['pos']) { $tmp[] = $row['pos']; } else { $tmp[] = $row['pos_ori']; } $tmp[] = $row['active']; $tmp[] = $row['gls']; $tmp[] = $row['fls']; $tmp[] = $row['ofs']; $tmp[] = $row['snt']; $tmp[] = $row['tsh']; $tmp[] = $row['crd']; $copystring .= implode(';', $tmp)."\n"; } $this->js("navigator.clipboard.writeText(`$copystring`)"); Notification::make() ->title('Results copied') ->success() ->send(); } public function calculateAspg($manual = false): void { if ($this->player_on_field_counter < 10) { foreach ($this->players as $k => $record) { $this->players[$k]['gls'] = ''; $this->players[$k]['fls'] = ''; $this->players[$k]['ofs'] = ''; $this->players[$k]['snt'] = ''; $this->players[$k]['tsh'] = ''; $this->players[$k]['crd'] = ''; } if ($manual) { Notification::make()->title('Calculation needs 10 player on field') ->info() ->send(); } return; } // Calcolare Aspettativa Team per GOALS // (il valore che appare quando viene selezionato un Evento): nell' esempio, // se scegliamo come Team il Remo (Home) il valore di riferimento sarà 1.2 $team_id = $this->team_id; $res = StatisticFixtures::where('id', $this->match_id)->first(); $asp_team = 0; if ((int) $res->home_id == (int) $team_id) { $asp_team = (float) $res->exp_home; } elseif ((int) $res->away_id == (int) $team_id) { $asp_team = (float) $res->exp_away; } $player = StatistikoDetail::where('ss_team_id', (int) $team_id)->where('is_active', 1)->get(); $count_player = 0; foreach ($player as $key => $value) { if ($value['position'] != 'GK' and $value['is_active'] == 1) { $count_player++; } } // Aspettativa Team di Riferimento // (ATR) = Aspettativa Team * Numero di Giocatori di Team in Rosters (esclusi i portieri) / 10. // Ad esempio per Remo (supponiamo 24 giocatori nel Roster esclusi i portieri): ATR = 1.2 * 24 / 10 = 2.88 $asp_team_riferimento = (float) $asp_team * $count_player / 10; // dd($player->count(), $asp_team_riferimento); $player_totals = SofaScorePlayerPerSeason::with('details')->where('season', 'total')->where('ss_team_id', $team_id)->get(); /*** "id" => 35067 "ss_player_id" => 233856 "ss_team_id" => 3212 "season" => "total" "total_events" => 12 "total_min" => 667 "average_min" => 56 "events_played_home" => 7 "events_played_away" => 0 "minutes_played_home" => 398 "minutes_played_away" => 274 "goals" => 0 "fouls" => 5 "cards" => 2 "offsides" => 0 "shots_on_target" => 1 "shots_off_target" => 0 */ $results = []; $this->calculationVariables = []; foreach ($player_totals as $val) { if ($val->details && $val->details->is_active) { $ss_player_id = $val->ss_player_id; $position = $val->details->position; $tmp = []; $tmp['id'] = $ss_player_id; $tmp['name'] = $val->details->player_name; $tmp['id_team'] = $team_id; $tmp['asp_team'] = $asp_team; $tmp['asp_team_riferimento'] = $asp_team_riferimento; $tmp['player_count_without_gk'] = $count_player; $position_field = $this->get_position($ss_player_id); if ($position_field) { $position = $position_field; $tmp['active'] = 1; } else { $tmp['active'] = 0; } $tmp['pos'] = $position; // Aspettativa di Gioco (AdG) = Somma Goals fatti da Player nel DB / Somma Minuti Giocati da Player (SMG) nel DB * 90. // Se la SMG è < Y per quel Player prenderemo in considerazione solo l'Aspettativa Statistica (AS). // Il valore Y dovrebbe essere configurabile in una interfaccia. Il valore iniziale lo fissiamo a Y = 180 // Somma Minuti Giocati da Player (SMG) nel DB $tmp['somma_minuti'] = $val->total_min; // il valore corrispondente al ruolo del Player (esempio un giocatore in Details ha ruolo = RW // quindi Aspettativa Statistica (AS) per RW = 0.219) // exp_goals // exp_assists // exp_cards // exp_fouls // exp_was_fouled // exp_offsides // exp_total_shots // exp_shots_on_target $bettypes = ['goals', 'cards', 'fouls', 'offsides', 'total_shots', 'shots_on_target']; foreach ($bettypes as $bettype) { $asp_statistica = (float) SofaScorePlayerPosition::where('ss_code', $position)->value('exp_'.$bettype); $tmp['asp_statistica_'.$bettype] = $asp_statistica; switch ($bettype) { case 'goals': if ($val->total_min < $this->y_value || $val->goals == 0) { $tmp['asp_gioco_'.$bettype] = $asp_statistica; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $asp_gioco = $val->goals / $val->total_min * 90; $tmp['asp_gioco_'.$bettype] = $asp_gioco; $tmp['asp_teorica_'.$bettype] = ($this->x_value * $asp_gioco + $asp_statistica) / (1 + $this->x_value); } break; case 'cards': if ($val->total_min < $this->y_value || $val->cards == 0) { $tmp['asp_gioco_'.$bettype] = $asp_statistica; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $asp_gioco = $val->cards / $val->total_min * 90; $tmp['asp_gioco_'.$bettype] = $asp_gioco; $tmp['asp_teorica_'.$bettype] = ($this->x_value * $asp_gioco + $asp_statistica) / (1 + $this->x_value); } break; case 'fouls': if ($val->total_min < $this->y_value || $val->fouls == 0) { $tmp['asp_gioco_'.$bettype] = $asp_statistica; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $asp_gioco = $val->fouls / $val->total_min * 90; $tmp['asp_gioco_'.$bettype] = $asp_gioco; $tmp['asp_teorica_'.$bettype] = ($this->x_value * $asp_gioco + $asp_statistica) / (1 + $this->x_value); } break; case 'offsides': if ($val->total_min < $this->y_value || $val->offsides == 0) { $tmp['asp_gioco_'.$bettype] = $asp_statistica; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $asp_gioco = $val->offsides / $val->total_min * 90; $tmp['asp_gioco_'.$bettype] = $asp_gioco; $tmp['asp_teorica_'.$bettype] = ($this->x_value * $asp_gioco + $asp_statistica) / (1 + $this->x_value); } break; case 'total_shots': if ($val->total_min < $this->y_value || $val->total_shots == 0) { $tmp['asp_gioco_'.$bettype] = $asp_statistica; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $asp_gioco = $val->total_shots / $val->total_min * 90; $tmp['asp_gioco_'.$bettype] = $asp_gioco; $tmp['asp_teorica_'.$bettype] = ($this->x_value * $asp_gioco + $asp_statistica) / (1 + $this->x_value); } break; case 'shots_on_target': if ($val->total_min < $this->y_value || $val->shots_on_target == 0) { $tmp['asp_gioco_'.$bettype] = $asp_statistica; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $asp_gioco = $val->shots_on_target / $val->total_min * 90; $tmp['asp_gioco_'.$bettype] = $asp_gioco; $tmp['asp_teorica_'.$bettype] = ($this->x_value * $asp_gioco + $asp_statistica) / (1 + $this->x_value); } break; } } // Calcolare la Somma di tutte le AT (colonna G della Tabella) // Considerare la ATR calcolata allo Step 1 (colonna I della Tabella) // Aspettativa per Player: AP = AT * ATR / TOT AT $results[] = $tmp; // for dev copy $this->calculationVariables[] = $tmp; } } Log::debug('results', $results); $bettypes = ['goals', 'cards', 'fouls', 'offsides', 'total_shots', 'shots_on_target']; foreach ($bettypes as $bettype) { $total_bettype = array_sum(array_column($results, 'asp_teorica_'.$bettype)); foreach ($results as $key => $value) { // Aspettativa per Player: AP = AT * ATR / TOT AT $results[$key]['asp_total_'.$bettype] = $total_bettype; // $results[$key]['asp_player_'.$bettype] = ((float) $value['asp_team'] * (float) $value['asp_teorica_'.$bettype]) / $total_bettype; $results[$key]['asp_player_'.$bettype] = ($asp_team * $asp_team_riferimento) / $total_bettype; } } foreach ($this->players as $k => $record) { foreach ($results as $key => $result) { if ((int) $record['id'] == (int) $result['id']) { $this->players[$k]['active'] = $result['active']; $this->players[$k]['gls'] = number_format($result['asp_player_goals'], 3); $this->players[$k]['fls'] = number_format($result['asp_player_fouls'], 3); $this->players[$k]['ofs'] = number_format($result['asp_player_offsides'], 3); $this->players[$k]['snt'] = number_format($result['asp_player_total_shots'], 3); $this->players[$k]['tsh'] = number_format($result['asp_player_shots_on_target'], 3); $this->players[$k]['crd'] = number_format($result['asp_player_cards'], 3); } } } $this->dispatch('update-players', players: $this->players); } public function get_position(int $ss_player_id) { // see if player is in field and if yes get new position foreach ($this->players as $record) { if ($record['id'] == $ss_player_id) { return $record['pos']; } } return false; } private function boxNames(): array { return [2 => 'DR', 4 => 'MR', 6 => 'LW', 9 => 'DC', 10 => 'DM', 11 => 'MC', 12 => 'AM', 15 => 'SW', 16 => 'DC', 17 => 'DM', 18 => 'MC', 19 => 'AM', 20 => 'SM', 21 => 'ST', 23 => 'DC', 24 => 'DM', 25 => 'MC', 26 => 'AM', 30 => 'DL', 32 => 'ML', 34 => 'RW']; } private function lineUpMap(): array { return [ '3313' => [9, 16, 23, 11, 18, 25, 19, 6, 34, 21], '3331' => [9, 16, 23, 17, 11, 25, 12, 19, 26, 21], '3331-' => [9, 16, 23, 10, 18, 24, 12, 19, 26, 21], '3331+' => [9, 16, 23, 11, 18, 25, 12, 19, 26, 21], '3412-' => [9, 16, 23, 4, 10, 24, 32, 19, 20, 21], '3412+' => [9, 16, 23, 4, 11, 25, 32, 19, 20, 21], '3421-' => [9, 16, 23, 4, 10, 24, 32, 12, 26, 21], '3421+' => [9, 16, 23, 4, 11, 25, 32, 12, 26, 21], '343-' => [9, 16, 23, 4, 10, 24, 32, 6, 34, 21], '343+' => [9, 16, 23, 4, 11, 25, 32, 6, 34, 21], '3511' => [9, 16, 23, 4, 11, 17, 25, 32, 19, 21], '3511-' => [9, 16, 23, 4, 10, 18, 24, 32, 19, 21], '3511+' => [9, 16, 23, 4, 11, 18, 25, 32, 19, 21], '352' => [9, 16, 23, 4, 11, 17, 25, 32, 20, 21], '352-' => [9, 16, 23, 4, 10, 18, 24, 32, 20, 21], '352+' => [9, 16, 23, 4, 11, 18, 25, 32, 20, 21], '4132' => [2, 9, 23, 30, 17, 12, 19, 26, 20, 21], '4213-' => [2, 9, 23, 30, 10, 24, 19, 6, 34, 21], '4213+' => [2, 9, 23, 30, 11, 25, 19, 6, 34, 21], '4222' => [2, 9, 23, 30, 10, 24, 12, 26, 20, 21], '4231' => [2, 9, 23, 30, 10, 24, 12, 19, 26, 21], '424' => [2, 9, 23, 30, 10, 24, 6, 34, 20, 21], '4312' => [2, 9, 23, 30, 17, 11, 25, 19, 20, 21], '4312-' => [2, 9, 23, 30, 10, 18, 24, 19, 20, 21], '4312+' => [2, 9, 23, 30, 11, 18, 25, 19, 20, 21], '4321' => [2, 9, 23, 30, 17, 11, 25, 12, 26, 21], '4321-' => [2, 9, 23, 30, 10, 18, 24, 12, 26, 21], '4321+' => [2, 9, 23, 30, 11, 18, 25, 12, 26, 21], '433' => [2, 9, 23, 30, 17, 11, 25, 6, 34, 21], '433-' => [2, 9, 23, 30, 10, 18, 24, 6, 34, 21], '433+' => [2, 9, 23, 30, 11, 18, 25, 6, 34, 21], '4411-' => [2, 9, 23, 30, 4, 10, 24, 32, 19, 21], '4411+' => [2, 9, 23, 30, 4, 11, 25, 32, 19, 21], '442' => [2, 9, 23, 30, 4, 17, 18, 32, 20, 21], '442-' => [2, 9, 23, 30, 4, 10, 24, 32, 20, 21], '442+' => [2, 9, 23, 30, 4, 11, 25, 32, 20, 21], '451' => [2, 9, 23, 30, 4, 17, 11, 25, 32, 21], '451-' => [2, 9, 23, 30, 4, 10, 18, 24, 32, 21], '451+' => [2, 9, 23, 30, 4, 11, 18, 25, 32, 21], '523-' => [2, 9, 16, 23, 30, 10, 24, 6, 34, 21], '523+' => [2, 9, 16, 23, 30, 11, 25, 6, 34, 21], '5311' => [2, 9, 16, 23, 30, 17, 11, 25, 19, 21], '5311-' => [2, 9, 16, 23, 30, 10, 18, 24, 19, 21], '5311+' => [2, 9, 16, 23, 30, 11, 18, 25, 19, 21], '532' => [2, 9, 16, 23, 30, 17, 11, 25, 20, 21], '532-' => [2, 9, 16, 23, 30, 10, 18, 24, 20, 21], '532+' => [2, 9, 16, 23, 30, 11, 18, 25, 20, 21], '541-' => [2, 9, 16, 23, 30, 4, 10, 24, 32, 21], '541+' => [2, 9, 16, 23, 30, 4, 11, 25, 32, 21], ]; } }