activeBoxes = BoxNames::load(); $this->lineUpMap = LineUpMap::load(); $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('clear-all')] public function clearAll() { $this->team_name = ''; $this->match_id = 0; for ($i = 1; $i <= 35; $i++) { $this->boxes[$i] = []; } $this->players = []; $this->dispatch('update-players', players: $this->players); } #[On('match-update')] public function matchUpdate(?int $match_id) { $this->team_name = ''; $this->match_id = 0; $this->players = []; for ($i = 1; $i <= 35; $i++) { $this->boxes[$i] = []; } if ($match_id) { $this->match_id = $match_id; } $this->dispatch('update-players', players: $this->players); } #[On('team-update')] public function syncData(?int $team_id) { if ($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(); } else { $this->team_name = ''; $this->clearResultTable(); $this->players = []; } } #[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++; } } } } // dd('here'); $this->calculateAspg(); } 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]['crd'] = ''; $this->players[$k]['snt'] = ''; $this->players[$k]['tsh'] = ''; } $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] = []; $this->players[$k]['active'] = 0; $this->players[$k]['gls'] = ''; $this->players[$k]['fls'] = ''; $this->players[$k]['ofs'] = ''; $this->players[$k]['crd'] = ''; $this->players[$k]['snt'] = ''; $this->players[$k]['tsh'] = ''; } $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', 'crd', 'snt', 'tsh']; $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['crd']; $tmp[] = $row['snt']; $tmp[] = $row['tsh']; $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]['crd'] = ''; $this->players[$k]['snt'] = ''; $this->players[$k]['tsh'] = ''; } $this->dispatch('update-players', players: $this->players); 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; $match = StatisticFixtures::where('id', $this->match_id)->first(); $asp_team = 0; $team_home_away = 'home'; if ((int) $match->home_id == (int) $team_id) { $asp_team = (float) $match->exp_home; $team_home_away = 'home'; } elseif ((int) $match->away_id == (int) $team_id) { $asp_team = (float) $match->exp_away; $team_home_away = 'away'; } $player_totals = SofaScorePlayerPerSeason::with('details')->where('total_min', '>', 0)->where('season', 'total')->where('ss_team_id', $team_id)->get(); $count_player = 0; foreach ($player_totals as $key => $value) { if ($value->details != null && $value->details->position != 'GK' && (int) $value->details->is_active != 0) { $count_player++; } } $results = []; foreach ($player_totals as $val) { if ($val->details != null && $val->details->position != 'GK' && (int) $val->details->is_active != 0) { /*** "goals" => 0 "fouls" => 13 "cards" => 3 "offsides" => 0 "shots_on_target" => 3 "shots_off_target" => 2 "total_shots" => 4 */ $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['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; $tmp['shots_on_target'] = $val->shots_on_target; $tmp['shots_off_target'] = $val->shots_off_target; $tmp['shots_blocked'] = $val->shots_blocked; // 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; // if ($val->ss_player_id == 243651) // dd($val, $asp_statistica); // if ($val->total_min < $this->y_value) { // $asp_gioco = 0; // } else { // $asp_gioco = $val->shots_on_target / $val->total_min * 90; // } switch ($bettype) { case 'goals': $asp_gioco = $val->goals / $val->total_min * 90; if ($asp_gioco == 0 || $val->total_min < $this->y_value) { $tmp['asp_gioco_'.$bettype] = 0; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $tmp['asp_gioco_'.$bettype] = $asp_gioco; $tmp['asp_teorica_'.$bettype] = ($this->x_value * $asp_gioco + $asp_statistica) / (1 + $this->x_value); } break; case 'cards': $asp_gioco = $val->cards / $val->total_min * 90; if ($asp_gioco == 0 || $val->total_min < $this->y_value) { $tmp['asp_gioco_'.$bettype] = 0; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $tmp['asp_gioco_'.$bettype] = $asp_gioco; $tmp['asp_teorica_'.$bettype] = ($this->x_value * $asp_gioco + $asp_statistica) / (1 + $this->x_value); } break; case 'fouls': $asp_gioco = $val->fouls / $val->total_min * 90; if ($asp_gioco == 0 || $val->total_min < $this->y_value) { $tmp['asp_gioco_'.$bettype] = 0; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $tmp['asp_gioco_'.$bettype] = $asp_gioco; $tmp['asp_teorica_'.$bettype] = ($this->x_value * $asp_gioco + $asp_statistica) / (1 + $this->x_value); } break; case 'offsides': $asp_gioco = $val->offsides / $val->total_min * 90; if ($asp_gioco == 0 || $val->total_min < $this->y_value) { $tmp['asp_gioco_'.$bettype] = 0; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $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': $asp_gioco = $val->total_shots / $val->total_min * 90; if ($asp_gioco == 0 || $val->total_min < $this->y_value) { $tmp['asp_gioco_'.$bettype] = 0; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $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': $asp_gioco = $val->shots_on_target / $val->total_min * 90; if ($asp_gioco == 0 || $val->total_min < $this->y_value) { $tmp['asp_gioco_'.$bettype] = 0; $tmp['asp_teorica_'.$bettype] = $asp_statistica; } else { $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; } } $asp_team_all = Expectations::load($match); // 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 $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) { switch ($bettype) { case 'goals': // Aspettativa per Player: AP = AT * ATR / TOT AT // $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; $asp_team_riferimento = (float) $asp_team * $count_player / 10; $results[$key]['asp_riferimento_goals'] = $asp_team_riferimento; $results[$key]['asp_player_'.$bettype] = $value['asp_teorica_'.$bettype] * $asp_team_riferimento / $total_bettype; $results[$key]['asp_total_'.$bettype] = $total_bettype; break; case 'cards': $asp_team_riferimento = (float) $asp_team_all[$team_home_away]['crd'] * $count_player / 10; $results[$key]['asp_team_riferimento_card'] = $asp_team_riferimento; $results[$key]['asp_total_'.$bettype] = $total_bettype; $results[$key]['asp_player_'.$bettype] = $value['asp_teorica_'.$bettype] * $asp_team_riferimento / $total_bettype; break; case 'fouls': $asp_team_riferimento = (float) $asp_team_all[$team_home_away]['fls'] * $count_player / 10; $results[$key]['asp_team_riferimento_fouls'] = $asp_team_riferimento; $results[$key]['asp_total_'.$bettype] = $total_bettype; $results[$key]['asp_player_'.$bettype] = $value['asp_teorica_'.$bettype] * $asp_team_riferimento / $total_bettype; break; case 'offsides': $asp_team_riferimento = (float) $asp_team_all[$team_home_away]['ofs'] * $count_player / 10; $results[$key]['asp_team_riferimento_offside'] = $asp_team_riferimento; $results[$key]['asp_total_'.$bettype] = $total_bettype; $results[$key]['asp_player_'.$bettype] = $value['asp_teorica_'.$bettype] * $asp_team_riferimento / $total_bettype; break; case 'total_shots': $asp_team_riferimento = (float) $asp_team_all[$team_home_away]['tsh'] * $count_player / 10; $results[$key]['asp_team_riferimento_tsh'] = $asp_team_riferimento; $results[$key]['asp_total_'.$bettype] = $total_bettype; $results[$key]['asp_player_'.$bettype] = $value['asp_teorica_'.$bettype] * $asp_team_riferimento / $total_bettype; break; case 'shots_on_target': $asp_team_riferimento = (float) $asp_team_all[$team_home_away]['snt'] * $count_player / 10; $results[$key]['asp_team_riferimento_snt'] = $asp_team_riferimento; $results[$key]['asp_total_'.$bettype] = $total_bettype; $results[$key]['asp_player_'.$bettype] = $value['asp_teorica_'.$bettype] * $asp_team_riferimento / $total_bettype; break; } } } $map = []; $res = ExpectedMinimumPosition::all(); foreach ($res as $val) { $map[$val->position]['gls'] = $val->gls; $map[$val->position]['crd'] = $val->crd; $map[$val->position]['fls'] = $val->fls; $map[$val->position]['ofs'] = $val->ofs; $map[$val->position]['tsh'] = $val->tsh; $map[$val->position]['snt'] = $val->snt; } // stesso ordine di prima: GLS, CRD, FLS, OFS, TSH, SNT foreach ($this->players as $k => $player) { foreach ($results as $key => $result) { if ((int) $player['id'] == (int) $result['id']) { $this->players[$k]['active'] = $result['active']; $pos = $this->players[$k]['pos']; if (! $pos) { $pos = $this->players[$k]['pos_ori']; } $tamx = number_format($map[$pos]['gls'], 3); $final = number_format($result['asp_player_goals'], 3); $results[$key]['finale_tamx_gls'] = $tamx; $results[$key]['finale_calc_gls'] = $final; $this->players[$k]['gls'] = (float) $final > (float) $tamx ? $final : $tamx; $tamx = number_format($map[$pos]['crd'], 3); $final = number_format($result['asp_player_cards'], 3); $results[$key]['finale_tamx_crd'] = $tamx; $results[$key]['finale_calc_crd'] = $final; $this->players[$k]['crd'] = (float) $final > (float) $tamx ? $final : $tamx; $tamx = number_format($map[$pos]['fls'], 3); $final = number_format($result['asp_player_fouls'], 3); $results[$key]['finale_tamx_fls'] = $tamx; $results[$key]['finale_calc_fls'] = $final; $this->players[$k]['fls'] = (float) $final > (float) $tamx ? $final : $tamx; $tamx = number_format($map[$pos]['ofs'], 3); $final = number_format($result['asp_player_offsides'], 3); $results[$key]['finale_tamx_ofs'] = $tamx; $results[$key]['finale_calc_ofs'] = $final; $this->players[$k]['ofs'] = (float) $final > (float) $tamx ? $final : $tamx; $tamx = number_format($map[$pos]['tsh'], 3); $final = number_format($result['asp_player_total_shots'], 3); $results[$key]['finale_tamx_tsh'] = $tamx; $results[$key]['finale_calc_tsh'] = $final; $this->players[$k]['tsh'] = (float) $final > (float) $tamx ? $final : $tamx; $tamx = number_format($map[$pos]['snt'], 3); $final = number_format($result['asp_player_shots_on_target'], 3); $results[$key]['finale_tamx_snt'] = $tamx; $results[$key]['finale_calc_snt'] = $final; $this->players[$k]['snt'] = (float) $final > (float) $tamx ? $final : $tamx; } } } $this->calculationVariables = $results; $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; } public function prepareLineUp() { $players = SofaScorePlayerPerSeason::with('details')->where('season', 'total')->where('ss_team_id', $this->team_id)->get(); $arr = collect(); foreach ($players as $value) { if ($value?->details->position ?? 0) { $arr->push([ 'id' => $value->ss_player_id, 'min' => $value->average_min, 'pos' => $value->details->position, 'name' => $value->details->player_name, ]); } } return $arr; } public function generateLineUp(): void { if ($this->activeLineUp && $this->team_id) { $players = $this->prepareLineUp(); $places = LineUpMap::get($this->activeLineUp); $lineup = []; $id_used = []; foreach ($places as $k => $place) { $this->getPlayerForPosition($lineup, $id_used, $place, $players); } for ($i = 1; $i <= 35; $i++) { $this->boxes[$i] = []; } $this->clearResultTable(); $this->player_on_field_counter = 0; foreach ($this->players as $k => $record) { $id = $record['id']; if (isset($lineup[$id])) { $this->boxes[$lineup[$id]['place']] = $record; $this->players[$k]['active'] = 1; $this->players[$k]['pos'] = $lineup[$id]['position']; $this->player_on_field_counter++; } else { $this->players[$k]['active'] = 0; $this->players[$k]['pos'] = ''; } } $this->calculateAspg(); $this->storePlacement(); } } public function majorFormations(): array { // 343+ // 352 // 433+ // 442+ // 4231 // 4321+ // 4312+ // 4411+ return [ '343+' => [9, 16, 23, 4, 11, 25, 32, 6, 34, 21], '352' => [9, 16, 23, 4, 11, 17, 25, 32, 20, 21], '433+' => [2, 9, 23, 30, 11, 18, 25, 6, 34, 21], '442+' => [2, 9, 23, 30, 4, 11, 25, 32, 20, 21], '4231' => [2, 9, 23, 30, 10, 24, 12, 19, 26, 21], '4321+' => [2, 9, 23, 30, 11, 18, 25, 12, 26, 21], '4312+' => [2, 9, 23, 30, 11, 18, 25, 19, 20, 21], '4411+' => [2, 9, 23, 30, 4, 11, 25, 32, 19, 21], ]; } public function generateBestLineUp(): void { if (! $this->team_id) { return; } $all_lineups = []; $players = $this->prepareLineUp(); $hirarchy = PositionHirarchie::load(); $major_formations = self::majorFormations(); foreach ($major_formations as $formation_name => $formation_positions) { $lineup = []; $id_used = []; foreach ($formation_positions as $place) { $this->getPlayerForPosition($lineup, $id_used, $place, $players); } $all_lineups[$formation_name] = $lineup; } $tmp = []; foreach ($all_lineups as $formation_name => $lineup) { $tmp[$formation_name] = array_sum(array_column($lineup, 'min')); } $formation_name = array_search(max($tmp), $tmp); $this->dispatch('update-lineup', $formation_name); $this->lineUpUpdate($formation_name); $this->generateLineUp(); } public function getPlayerForPosition(array &$lineup, array &$id_used, int $place, Collection $players) { $position = $this->activeBoxes[$place]; $hirarchy = PositionHirarchie::load(); $fitered = $players->where('pos', $position)->whereNotIn('id', $id_used)->sortByDesc('min')->first(); dd($fitered, $position); if (isset($fitered['id'])) { $lineup[$fitered['id']] = ['id' => $fitered['id'], 'place' => $place, 'position' => $position]; $id_used[] = $fitered['id']; } else { if (isset($hirarchy[$position])) { $position = $hirarchy[$position][0]; $fitered = $players->where('pos', $position)->whereNotIn('id', $id_used)->sortByDesc('min')->first(); if (isset($fitered['id'])) { $lineup[$fitered['id']] = ['id' => $fitered['id'], 'place' => $place, 'position' => $position]; $id_used[] = $fitered['id']; } elseif (isset($hirarchy[$position][1])) { $position = $hirarchy[$position][1]; $fitered = $players->where('pos', $position)->whereNotIn('id', $id_used)->sortByDesc('min')->first(); if (isset($fitered['id'])) { $lineup[$fitered['id']] = ['id' => $fitered['id'], 'place' => $place, 'position' => $position]; $id_used[] = $fitered['id']; } elseif (isset($hirarchy[$position][2])) { $position = $hirarchy[$position][2]; $fitered = $players->where('pos', $position)->whereNotIn('id', $id_used)->sortByDesc('min')->first(); if (isset($fitered['id'])) { $lineup[$fitered['id']] = ['id' => $fitered['id'], 'place' => $place, 'position' => $position]; $id_used[] = $fitered['id']; } } } } } } }