Compare commits
4 Commits
6cd253d5f0
...
main
Author | SHA1 | Date | |
---|---|---|---|
d78e07f513
|
|||
fc073de1de
|
|||
1d945977dc
|
|||
1fda84bdef
|
@@ -38,20 +38,33 @@ def load_stats():
|
||||
|
||||
def team_table_json():
|
||||
players, preferences = load_stats()
|
||||
mean, team0, team1 = apply_brute_force(players, preferences)
|
||||
data = {}
|
||||
for i, team in enumerate([team0, team1]):
|
||||
tablename = f"Team {i+1}"
|
||||
data[tablename] = []
|
||||
for p in sorted(list(team)):
|
||||
prefs = preferences[p]
|
||||
matches = sum([pref in team for pref in preferences[p]])
|
||||
data[tablename].append([p, matches, len(prefs)])
|
||||
best = apply_brute_force(players, preferences)
|
||||
data = {k: {} for k in best}
|
||||
for k, v in best.items():
|
||||
mean, team0, team1 = v[0]
|
||||
overall_matches = 0
|
||||
overall_preference_statements = 0
|
||||
for i, team in enumerate([team0, team1]):
|
||||
tablename = f"Team {i+1}"
|
||||
data[k][tablename] = []
|
||||
for p in sorted(list(team)):
|
||||
prefs = preferences[p]
|
||||
matches = sum([pref in team for pref in preferences[p]])
|
||||
data[k][tablename].append([p, matches, len(prefs)])
|
||||
overall_matches += matches
|
||||
overall_preference_statements += len(prefs)
|
||||
# data[k]["overall_matches"] = overall_matches
|
||||
# data[k]["overall_preference_statements"] = overall_preference_statements
|
||||
|
||||
with open("prefs_page/src/table.json", "w") as f:
|
||||
json.dump(data, f)
|
||||
|
||||
|
||||
def unique_names(team):
|
||||
"""check if first names are unique"""
|
||||
return len(set(team)) == len(set([p.split()[0] for p in team]))
|
||||
|
||||
|
||||
def apply_brute_force(players, preferences):
|
||||
def evaluate_teams(team0, team1):
|
||||
scores = []
|
||||
@@ -63,33 +76,43 @@ def apply_brute_force(players, preferences):
|
||||
percentages.append(scores[-1] / len(preferences[p]))
|
||||
return np.mean(scores), np.mean(percentages) * 100
|
||||
|
||||
best_score = [(0, [], [])]
|
||||
best_percentage = [(0, [], [])]
|
||||
best = {
|
||||
f"{i},{j}": [(0, [], [])]
|
||||
for i, j in itertools.product(["total", "relative"], ["unique", "non-unique"])
|
||||
}
|
||||
|
||||
for team0 in itertools.combinations(players, 9):
|
||||
team1 = {player for player in players if player not in team0}
|
||||
score, percentage = evaluate_teams(team0, team1)
|
||||
if score > best_score[0][0]:
|
||||
best_score = [(score, team0, team1)]
|
||||
if score == best_score[0][0] and set(team0) != set(best_score[0][1]):
|
||||
best_score.append((score, team0, team1))
|
||||
if percentage > best_percentage[0][0]:
|
||||
best_percentage = [(percentage, team0, team1)]
|
||||
if percentage == best_percentage[0][0] and set(team0) != set(best_score[0][1]):
|
||||
best_percentage.append((percentage, team0, team1))
|
||||
for k, v in best.items():
|
||||
if k.startswith("total"):
|
||||
meassure = score
|
||||
elif k.startswith("relative"):
|
||||
meassure = percentage
|
||||
if meassure > best[k][0][0]:
|
||||
if k.endswith(",unique") and not (
|
||||
unique_names(team0) and unique_names(team1)
|
||||
):
|
||||
continue
|
||||
best[k] = [(meassure, team0, team1)]
|
||||
elif meassure == best[k][0][0] and set(team0) != set(best[k][0][1]):
|
||||
if k.endswith(",unique") and not (
|
||||
unique_names(team0) and unique_names(team1)
|
||||
):
|
||||
continue
|
||||
best[k].append((meassure, team0, team1))
|
||||
|
||||
if __name__ == "__main__":
|
||||
for result in best_score:
|
||||
print(result[0])
|
||||
print(result[1])
|
||||
print(result[2])
|
||||
|
||||
for result in best_percentage:
|
||||
print(result[0])
|
||||
print(result[1])
|
||||
print(result[2])
|
||||
for k, v in best.items():
|
||||
print("##", k)
|
||||
for result in v:
|
||||
print(result[0])
|
||||
print(sorted(result[1]))
|
||||
print(sorted(result[2]))
|
||||
print()
|
||||
|
||||
# team_table(score, team0, team1)
|
||||
return best_score[0]
|
||||
return best
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#root {
|
||||
max-width: 60vw;
|
||||
max-width: 70vw;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
@@ -11,4 +11,5 @@
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
padding: 0;
|
||||
}
|
||||
|
@@ -200,9 +200,17 @@ function App() {
|
||||
{SubmitButton({ person, players })}
|
||||
<p>now: click submit.</p>
|
||||
</div>
|
||||
<p className="read-the-docs">
|
||||
suggested teams are not updated right away. don't try to hack the
|
||||
algorithm ;D
|
||||
</p>
|
||||
{TeamTables()}
|
||||
<p className="read-the-docs">
|
||||
something not working? message <a href="https://t.me/x0124816">me</a>.
|
||||
sources:{" "}
|
||||
<a href="https://git.0124816.xyz/julius/teambuilding" key="gitea">
|
||||
<img src="gitea.svg" alt="gitea" height="20" />
|
||||
</a>
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import * as React from "react";
|
||||
import { useState } from "react";
|
||||
import Table from "@mui/material/Table";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import TableCell from "@mui/material/TableCell";
|
||||
@@ -7,13 +7,50 @@ import TableHead from "@mui/material/TableHead";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import data from "./table.json";
|
||||
import {
|
||||
Box,
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
Stack,
|
||||
Switch,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
|
||||
export default function TeamTables() {
|
||||
interface Data {
|
||||
[index: string]: Teams;
|
||||
}
|
||||
|
||||
interface Teams {
|
||||
teamname: Row;
|
||||
}
|
||||
|
||||
type Row = [player: string, fulfilled: number, total: number];
|
||||
|
||||
function RenderTable(data: object) {
|
||||
let nMatches: number = 0;
|
||||
let nTotal: number = 0;
|
||||
let nPlayers: number = 0;
|
||||
let relativeScore: number = 0.0;
|
||||
for (const rows of Object.values(data)) {
|
||||
for (const row of rows) {
|
||||
nMatches += row[1];
|
||||
nTotal += row[2];
|
||||
relativeScore += row[1] / row[2];
|
||||
nPlayers++;
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{Object.keys(data).map((teamname) => (
|
||||
<Paper elevation={2} sx={{ p: 2, display: "inline-block" }}>
|
||||
average wishes fulfilled:{" "}
|
||||
<Typography sx={{ fontFamily: "monospace" }}>
|
||||
{(nMatches / nPlayers).toPrecision(2)} (
|
||||
{((relativeScore / nPlayers) * 100).toPrecision(3)}%)
|
||||
</Typography>
|
||||
</Paper>
|
||||
{Object.entries(data).map(([teamname, rows]) => (
|
||||
<>
|
||||
<h1>{teamname as String}</h1>
|
||||
<h1>{teamname}</h1>
|
||||
<TableContainer component={Paper}>
|
||||
<Table
|
||||
sx={{ m: "8px auto" }}
|
||||
@@ -27,7 +64,7 @@ export default function TeamTables() {
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{data[teamname].map((row) => (
|
||||
{(rows as Row[]).map((row: Row) => (
|
||||
<TableRow
|
||||
key={row[0]}
|
||||
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
|
||||
@@ -46,3 +83,69 @@ export default function TeamTables() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function TeamTables() {
|
||||
const [total, setTotal] = useState("relative");
|
||||
const [unique, setUnique] = useState("non-unique");
|
||||
|
||||
const handleTotalChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.checked) {
|
||||
setTotal("relative");
|
||||
} else {
|
||||
setTotal("total");
|
||||
}
|
||||
};
|
||||
|
||||
const handleUniqueChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.checked) {
|
||||
setUnique("unique");
|
||||
} else {
|
||||
setUnique("non-unique");
|
||||
}
|
||||
};
|
||||
|
||||
let tabledata: Data = data as unknown as Data;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
m: "auto",
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Paper elevation={2} sx={{ m: 1, p: 1 }}>
|
||||
<Typography className="read-the-docs">according to</Typography>
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={1}
|
||||
sx={{ p: "0 16px", m: "0 8px", alignItems: "center" }}
|
||||
>
|
||||
<Typography>total</Typography>
|
||||
<Switch defaultChecked onChange={handleTotalChange} />
|
||||
<Typography>relative</Typography>
|
||||
</Stack>
|
||||
<Typography className="read-the-docs">
|
||||
number of wishes fulfilled
|
||||
</Typography>
|
||||
</Paper>
|
||||
|
||||
<Paper elevation={2} sx={{ m: 1, p: 1, justifyContent: "center" }}>
|
||||
<FormControlLabel
|
||||
sx={{ padding: 2, m: 1 }}
|
||||
control={
|
||||
<Checkbox
|
||||
checked={unique === "unique"}
|
||||
onChange={handleUniqueChange}
|
||||
/>
|
||||
}
|
||||
label="unique first names"
|
||||
/>
|
||||
</Paper>
|
||||
</Box>
|
||||
{RenderTable(tabledata[[total, unique].join(",") as string])}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user