5
0
mirror of https://github.com/AJMicke/KickerELO.git synced 2026-03-11 13:31:02 +01:00
This commit is contained in:
2025-05-11 17:17:32 +02:00
6 changed files with 131 additions and 6 deletions

View File

@@ -64,7 +64,8 @@ public class KickerAppLayout extends AppLayout {
nav2.setCollapsible(true);
nav2.addItem(new SideNavItem("Ergebnis eintragen", Enter2vs2View.class, VaadinIcon.EDIT.create()),
new SideNavItem("ELO-Graph", Graph2vs2View.class, VaadinIcon.BAR_CHART.create()),
new SideNavItem("Historie", History2vs2View.class, VaadinIcon.RECORDS.create()));
new SideNavItem("Historie", History2vs2View.class, VaadinIcon.RECORDS.create()),
new SideNavItem("Statistik", Stat2vs2View.class, VaadinIcon.ABACUS.create()));
Image githubLogo = new Image("github-mark.png", "Github");

View File

@@ -1,9 +1,18 @@
package org.kickerelo.kickerelo.repository;
import org.kickerelo.kickerelo.data.Ergebnis2vs2;
import org.kickerelo.kickerelo.data.Spieler;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface Ergebnis2vs2Repository extends JpaRepository<Ergebnis2vs2, Long> {
int countByGewinnerHinten(Spieler gewinnerHinten);
int countByGewinnerVorn(Spieler gewinnerVon);
int countByVerliererHinten(Spieler verliererHinten);
int countByVerliererVorn(Spieler verlierVon);
int countByGewinnerVornOrGewinnerHinten(Spieler gewinnerVon, Spieler gewinnerHinten);
int countByGewinnerVornOrGewinnerHintenOrVerliererVornOrVerliererHinten(Spieler gewinnerVon, Spieler gewinnerHinten,
Spieler verliererVon, Spieler verliererHinten);
}

View File

@@ -21,13 +21,13 @@ public class EloCalculationService {
public void updateElo1vs1(Spieler gewinner, Spieler verlierer, short toreVerlierer) {
final float baseK = 50;
final float reductionPerGoal = 0.1f * baseK;
final float finalK = baseK - (reductionPerGoal * toreVerlierer);
float expectedScoreWinner = (float) (1 / (1 + Math.pow(10, (verlierer.getElo1vs1() - gewinner.getElo1vs1()) / 400)));
float expectedScoreLoser = (float) (1 / (1 + Math.pow(10, (gewinner.getElo1vs1() - verlierer.getElo1vs1()) / 400)));
gewinner.setElo1vs1(gewinner.getElo1vs1() + finalK * (1-expectedScoreWinner));
verlierer.setElo1vs1(verlierer.getElo1vs1() - finalK * expectedScoreLoser);
double x = Math.pow(10, (verlierer.getElo1vs1() - gewinner.getElo1vs1()) / 400);
float eloChange = (float) (finalK * x / (x + 1));
gewinner.setElo1vs1(gewinner.getElo1vs1() + eloChange);
verlierer.setElo1vs1(verlierer.getElo1vs1() - eloChange);
}
/**

View File

@@ -0,0 +1,42 @@
package org.kickerelo.kickerelo.service;
import org.kickerelo.kickerelo.data.Spieler;
import org.kickerelo.kickerelo.repository.Ergebnis2vs2Repository;
import org.kickerelo.kickerelo.repository.SpielerRepository;
import org.kickerelo.kickerelo.util.Position;
import org.springframework.stereotype.Service;
@Service
public class Stat2vs2Service {
Ergebnis2vs2Repository ergebnis2vs2Repository;
SpielerRepository spielerRepository;
public Stat2vs2Service(Ergebnis2vs2Repository ergebnis2vs2Repository, SpielerRepository spielerRepository) {
this.ergebnis2vs2Repository = ergebnis2vs2Repository;
this.spielerRepository = spielerRepository;
}
public Float getWinrate(Spieler s, Position p) {
int wins, losses;
switch (p) {
case BACK:
wins = ergebnis2vs2Repository.countByGewinnerHinten(s);
losses = ergebnis2vs2Repository.countByVerliererHinten(s);
break;
case FRONT:
wins = ergebnis2vs2Repository.countByGewinnerVorn(s);
losses = ergebnis2vs2Repository.countByVerliererVorn(s);
break;
default:
wins = 0;
losses = 0;
}
return (float) wins / (wins+losses);
}
public Float getFrontRate(Spieler s) {
int numFront = ergebnis2vs2Repository.countByGewinnerVornOrGewinnerHinten(s, s);
int numAll = ergebnis2vs2Repository.countByGewinnerVornOrGewinnerHintenOrVerliererVornOrVerliererHinten(s, s, s, s);
return (float) numFront / numAll;
}
}

View File

@@ -0,0 +1,5 @@
package org.kickerelo.kickerelo.util;
public enum Position {
FRONT, BACK
}

View File

@@ -0,0 +1,68 @@
package org.kickerelo.kickerelo.views;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.html.NativeLabel;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.progressbar.ProgressBar;
import com.vaadin.flow.component.progressbar.ProgressBarVariant;
import com.vaadin.flow.router.Route;
import org.kickerelo.kickerelo.data.Spieler;
import org.kickerelo.kickerelo.service.KickerEloService;
import org.kickerelo.kickerelo.service.Stat2vs2Service;
import org.kickerelo.kickerelo.util.Position;
@Route("stat2vs2")
public class Stat2vs2View extends VerticalLayout {
Stat2vs2Service stat2vs2Service;
KickerEloService kickerEloService;
H2 subheading;
ComboBox<Spieler> selector;
ProgressBar frontRate = new ProgressBar();
NativeLabel frontRateText = new NativeLabel();
ProgressBar winRateFront = new ProgressBar();
NativeLabel winRateFrontText = new NativeLabel();
ProgressBar winRateBack = new ProgressBar();
NativeLabel winRateBackText = new NativeLabel();
public Stat2vs2View(Stat2vs2Service service, KickerEloService kickerService) {
this.stat2vs2Service = service;
this.kickerEloService = kickerService;
subheading = new H2("2 vs 2 Ergebnis");
selector = new ComboBox<>("Spieler");
selector.setItems(kickerService.getSpielerEntities());
selector.addValueChangeListener(event -> updateData(selector.getValue()));
add(subheading, selector, frontRateText, frontRate, winRateFrontText, winRateFront, winRateBackText, winRateBack);
}
private void updateData(Spieler s) {
updateFrontRate(s);
updateFrontWinrate(s);
updateBackWinrate(s);
}
private void updateFrontRate(Spieler s) {
String text = "Anteil Spiele vorne: ";
Float rateFrontGames = stat2vs2Service.getFrontRate(s);
frontRate.setValue(rateFrontGames);
frontRateText.setText(rateFrontGames.isNaN() ? text + "-" : text + String.format("%.2f", rateFrontGames * 100) + "%");
}
private void updateFrontWinrate(Spieler s) {
String text = "Winrate vorne: ";
Float winRate = stat2vs2Service.getWinrate(s, Position.FRONT);
winRateFront.setValue(winRate);
winRateFront.removeThemeVariants(ProgressBarVariant.LUMO_SUCCESS, ProgressBarVariant.LUMO_ERROR);
winRateFront.addThemeVariants((winRate > 0.5f ? ProgressBarVariant.LUMO_SUCCESS : ProgressBarVariant.LUMO_ERROR));
winRateFrontText.setText(winRate.isNaN() ? text + "-" : text + String.format("%.2f", winRate * 100) + "%");
}
private void updateBackWinrate(Spieler s) {
String text = "Winrate hinten: ";
Float winRate = stat2vs2Service.getWinrate(s, Position.BACK);
winRateBack.setValue(winRate);
winRateBack.removeThemeVariants(ProgressBarVariant.LUMO_SUCCESS, ProgressBarVariant.LUMO_ERROR);
winRateBack.addThemeVariants((winRate > 0.5f ? ProgressBarVariant.LUMO_SUCCESS : ProgressBarVariant.LUMO_ERROR));
winRateBackText.setText(winRate.isNaN() ? text + "-" : text + String.format("%.2f", winRate * 100) + "%");
}
}