slevis commited on
Commit
4efefa6
·
verified ·
1 Parent(s): 5ab9912

Add ramsch game type

Browse files
Files changed (1) hide show
  1. app.py +107 -39
app.py CHANGED
@@ -9,12 +9,13 @@ from pathlib import Path
9
  GRUNDWERTE = {"Karo": 9, "Herz": 10, "Pik": 11, "Kreuz": 12, "Grand": 24}
10
  NULL_SPIELE = {"Null": 23, "Null Hand": 35, "Null Ouvert": 46, "Null Hand Ouvert": 59}
11
  SPIELER = ["Kirsten", "Robert", "Samuel"]
 
 
12
  HISTORY_DF_HEADERS = ["Kirsten", "Robert", "Samuel", "Spielwert", "Spielart", "Alleinspieler", "Details", "Verloren"]
13
 
14
  # --- Hugging Face Configuration ---
15
- # Define a more descriptive local folder for saving tournament files before upload.
16
  LOCAL_TOURNAMENT_DIR = Path("saved_tournaments/")
17
- LOCAL_TOURNAMENT_DIR.mkdir(exist_ok=True) # Ensure the directory exists
18
 
19
  token = os.getenv('dataset_access_token')
20
 
@@ -37,8 +38,47 @@ def calculate_spielwert(spielart, spitzen_str, hand, schneider, schwarz, schneid
37
  grundwert = GRUNDWERTE[spielart]
38
  return (spitzen_anzahl + gewinnstufe) * grundwert
39
 
40
- def spiel_hinzufuegen(history_df, spieler, spielart, spitzen, hand, schneider, schwarz, schneider_angesagt, schwarz_angesagt, offen, verloren):
41
  """Adds a new game to the history DataFrame and dynamically calculates the total scores."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  spielwert = calculate_spielwert(spielart, spitzen, hand, schneider, schwarz, schneider_angesagt, schwarz_angesagt, offen)
43
 
44
  neue_punkte = {name: 0 for name in SPIELER}
@@ -49,7 +89,7 @@ def spiel_hinzufuegen(history_df, spieler, spielart, spitzen, hand, schneider, s
49
  for p in SPIELER:
50
  if p != spieler:
51
  neue_punkte[p] = -40
52
- else:
53
  neue_punkte[spieler] = -50 - (2 * spielwert)
54
  for p in SPIELER:
55
  if p != spieler:
@@ -74,11 +114,12 @@ def spiel_hinzufuegen(history_df, spieler, spielart, spitzen, hand, schneider, s
74
 
75
  new_row_df = pd.DataFrame([neues_spiel_eintrag])
76
  updated_history_df = pd.concat([history_df, new_row_df], ignore_index=True)
77
- total_scores = updated_history_df[SPIELER].sum()
78
  totals_df = pd.DataFrame([total_scores])
79
 
80
  return totals_df, updated_history_df
81
 
 
82
  def reset_turnier():
83
  """Resets the entire score and history."""
84
  empty_totals = pd.DataFrame([{"Kirsten": 0, "Robert": 0, "Samuel": 0}])
@@ -87,27 +128,16 @@ def reset_turnier():
87
 
88
  def save_turnier_to_hf(history_df):
89
  """Saves the current tournament history to a local JSON file and immediately uploads it to the Hugging Face Hub."""
90
- # Check for Hugging Face token
91
  if HfFolder.get_token() is None:
92
  return "Hugging Face Token nicht gefunden. Bitte via `huggingface-cli login` anmelden."
93
-
94
- # Prevent saving an empty tournament
95
  if history_df.empty:
96
  return "Keine Spieldaten zum Speichern vorhanden."
97
-
98
- # Generate a unique filename for the tournament data to avoid overwriting files.
99
  tournament_filename = f"skat_tournament_{uuid.uuid4()}.jsonl"
100
  local_file_path = LOCAL_TOURNAMENT_DIR / tournament_filename
101
-
102
- # Save the DataFrame to a local JSON Lines file.
103
  history_df.to_json(local_file_path, orient="records", lines=True, force_ascii=False)
104
-
105
- # Instantiate the HfApi client to upload the file.
106
  api = HfApi()
107
- repo_id = "slevis/skat-scores" # A more descriptive repository name
108
-
109
  try:
110
- # Upload the file directly. The repo will be created if it doesn't exist.
111
  api.upload_file(
112
  path_or_fileobj=local_file_path,
113
  path_in_repo=f"data/{tournament_filename}",
@@ -119,7 +149,6 @@ def save_turnier_to_hf(history_df):
119
  except Exception as e:
120
  return f"Fehler beim Upload: {e}"
121
 
122
-
123
  # --- UI Definition with Gradio ---
124
 
125
  with gr.Blocks() as demo:
@@ -139,26 +168,39 @@ with gr.Blocks() as demo:
139
  with gr.Column(scale=1):
140
  gr.Markdown("### Neues Spiel eingeben")
141
 
142
- spieler_input = gr.Dropdown(SPIELER, label="Alleinspieler")
143
  spielart_input = gr.Dropdown(
144
- choices=['Karo', 'Herz', 'Pik', 'Kreuz', 'Grand', 'Null', 'Null Hand', 'Null Ouvert', 'Null Hand Ouvert'],
145
  label="Spielart"
146
  )
147
- spitzen_input = gr.Dropdown(
148
- choices=[f"{m} {i}" for m in ["Mit", "Ohne"] for i in range(1, 5)],
149
- label="Spitzen"
150
- )
151
 
152
- with gr.Row():
153
- schneider_input = gr.Checkbox(label="Schneider")
154
- schwarz_input = gr.Checkbox(label="Schwarz")
155
- verloren_input = gr.Checkbox(label="Verloren?")
156
-
157
- with gr.Accordion("Optionen für Handspiele", open=False):
158
- hand_input = gr.Checkbox(label="Handspiel")
159
- schneider_angesagt_input = gr.Checkbox(label="Schneider angesagt")
160
- schwarz_angesagt_input = gr.Checkbox(label="Schwarz angesagt")
161
- offen_input = gr.Checkbox(label="Offen / Ouvert")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
  with gr.Row():
164
  speichere_spiel = gr.Button("Speichere Spiel", variant="primary", scale=2)
@@ -177,16 +219,43 @@ with gr.Blocks() as demo:
177
  wrap=True
178
  )
179
 
180
- inputs_list = [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  spieler_input, spielart_input, spitzen_input,
182
  hand_input, schneider_input, schwarz_input,
183
  schneider_angesagt_input, schwarz_angesagt_input, offen_input,
184
- verloren_input
 
 
185
  ]
186
 
187
  speichere_spiel.click(
188
  fn=spiel_hinzufuegen,
189
- inputs=[turnier_output] + inputs_list,
190
  outputs=[totals_output, turnier_output]
191
  )
192
 
@@ -196,7 +265,6 @@ with gr.Blocks() as demo:
196
  outputs=[totals_output, turnier_output]
197
  )
198
 
199
- # --- Click Handler for the Hugging Face Button ---
200
  save_to_hf_button.click(
201
  fn=save_turnier_to_hf,
202
  inputs=[turnier_output],
@@ -204,4 +272,4 @@ with gr.Blocks() as demo:
204
  )
205
 
206
  if __name__ == "__main__":
207
- demo.launch(share=True)
 
9
  GRUNDWERTE = {"Karo": 9, "Herz": 10, "Pik": 11, "Kreuz": 12, "Grand": 24}
10
  NULL_SPIELE = {"Null": 23, "Null Hand": 35, "Null Ouvert": 46, "Null Hand Ouvert": 59}
11
  SPIELER = ["Kirsten", "Robert", "Samuel"]
12
+ # Added a new game type 'Ramsch' to the list of choices
13
+ SPIELARTEN = ['Karo', 'Herz', 'Pik', 'Kreuz', 'Grand', 'Null', 'Null Hand', 'Null Ouvert', 'Null Hand Ouvert', 'Ramsch']
14
  HISTORY_DF_HEADERS = ["Kirsten", "Robert", "Samuel", "Spielwert", "Spielart", "Alleinspieler", "Details", "Verloren"]
15
 
16
  # --- Hugging Face Configuration ---
 
17
  LOCAL_TOURNAMENT_DIR = Path("saved_tournaments/")
18
+ LOCAL_TOURNAMENT_DIR.mkdir(exist_ok=True)
19
 
20
  token = os.getenv('dataset_access_token')
21
 
 
38
  grundwert = GRUNDWERTE[spielart]
39
  return (spitzen_anzahl + gewinnstufe) * grundwert
40
 
41
+ def spiel_hinzufuegen(history_df, spieler, spielart, spitzen, hand, schneider, schwarz, schneider_angesagt, schwarz_angesagt, offen, verloren, ramsch_verlierer=None, ramsch_punkte=None, ramsch_geschoben=None):
42
  """Adds a new game to the history DataFrame and dynamically calculates the total scores."""
43
+
44
+ # --- New logic for 'Ramsch' game type ---
45
+ if spielart == 'Ramsch':
46
+ if not ramsch_verlierer or not isinstance(ramsch_punkte, (int, float)) or ramsch_punkte <= 0:
47
+ # Return current state if Ramsch inputs are invalid or no points were made.
48
+ total_scores = history_df[SPIELER].sum() if not history_df.empty else {s: 0 for s in SPIELER}
49
+ totals_df = pd.DataFrame([total_scores])
50
+ return totals_df, history_df
51
+
52
+ # Per user request: a negative score for the loser based on their points and how often the skat was passed ("geschoben").
53
+ # A standard rule is that each "schieben" doubles the game's value.
54
+ # Final score = loser_points * (2 ** number_of_passes). This is robust and handles the 0-pass case correctly.
55
+ spielwert = ramsch_punkte * (2 ** ramsch_geschoben)
56
+
57
+ neue_punkte = {name: 0 for name in SPIELER}
58
+ # Only the loser's score is affected, as specified.
59
+ neue_punkte[ramsch_verlierer] = -spielwert
60
+
61
+ details = f"Augen: {int(ramsch_punkte)}, Geschoben: {ramsch_geschoben} mal"
62
+
63
+ neues_spiel_eintrag = {
64
+ "Kirsten": neue_punkte["Kirsten"],
65
+ "Robert": neue_punkte["Robert"],
66
+ "Samuel": neue_punkte["Samuel"],
67
+ "Spielwert": spielwert,
68
+ "Spielart": "Ramsch",
69
+ "Alleinspieler": "N/A", # No soloist in Ramsch
70
+ "Details": details,
71
+ "Verloren": "Ja" # A Ramsch game always has a loser
72
+ }
73
+
74
+ new_row_df = pd.DataFrame([neues_spiel_eintrag])
75
+ updated_history_df = pd.concat([history_df, new_row_df], ignore_index=True)
76
+ total_scores = updated_history_df[SPIELER].sum().astype(int)
77
+ totals_df = pd.DataFrame([total_scores])
78
+
79
+ return totals_df, updated_history_df
80
+
81
+ # --- Original logic for standard games ---
82
  spielwert = calculate_spielwert(spielart, spitzen, hand, schneider, schwarz, schneider_angesagt, schwarz_angesagt, offen)
83
 
84
  neue_punkte = {name: 0 for name in SPIELER}
 
89
  for p in SPIELER:
90
  if p != spieler:
91
  neue_punkte[p] = -40
92
+ else: # Game lost
93
  neue_punkte[spieler] = -50 - (2 * spielwert)
94
  for p in SPIELER:
95
  if p != spieler:
 
114
 
115
  new_row_df = pd.DataFrame([neues_spiel_eintrag])
116
  updated_history_df = pd.concat([history_df, new_row_df], ignore_index=True)
117
+ total_scores = updated_history_df[SPIELER].sum().astype(int)
118
  totals_df = pd.DataFrame([total_scores])
119
 
120
  return totals_df, updated_history_df
121
 
122
+
123
  def reset_turnier():
124
  """Resets the entire score and history."""
125
  empty_totals = pd.DataFrame([{"Kirsten": 0, "Robert": 0, "Samuel": 0}])
 
128
 
129
  def save_turnier_to_hf(history_df):
130
  """Saves the current tournament history to a local JSON file and immediately uploads it to the Hugging Face Hub."""
 
131
  if HfFolder.get_token() is None:
132
  return "Hugging Face Token nicht gefunden. Bitte via `huggingface-cli login` anmelden."
 
 
133
  if history_df.empty:
134
  return "Keine Spieldaten zum Speichern vorhanden."
 
 
135
  tournament_filename = f"skat_tournament_{uuid.uuid4()}.jsonl"
136
  local_file_path = LOCAL_TOURNAMENT_DIR / tournament_filename
 
 
137
  history_df.to_json(local_file_path, orient="records", lines=True, force_ascii=False)
 
 
138
  api = HfApi()
139
+ repo_id = "slevis/skat-scores"
 
140
  try:
 
141
  api.upload_file(
142
  path_or_fileobj=local_file_path,
143
  path_in_repo=f"data/{tournament_filename}",
 
149
  except Exception as e:
150
  return f"Fehler beim Upload: {e}"
151
 
 
152
  # --- UI Definition with Gradio ---
153
 
154
  with gr.Blocks() as demo:
 
168
  with gr.Column(scale=1):
169
  gr.Markdown("### Neues Spiel eingeben")
170
 
 
171
  spielart_input = gr.Dropdown(
172
+ choices=SPIELARTEN,
173
  label="Spielart"
174
  )
 
 
 
 
175
 
176
+ # --- Container for Standard Game Inputs (visible by default) ---
177
+ with gr.Group(visible=True) as standard_spiel_group:
178
+ gr.Markdown("#### Standard-Spiel")
179
+ spieler_input = gr.Dropdown(SPIELER, label="Alleinspieler")
180
+ spitzen_input = gr.Dropdown(
181
+ choices=[f"{m} {i}" for m in ["Mit", "Ohne"] for i in range(1, 5)],
182
+ label="Spitzen"
183
+ )
184
+ with gr.Row():
185
+ schneider_input = gr.Checkbox(label="Schneider")
186
+ schwarz_input = gr.Checkbox(label="Schwarz")
187
+ verloren_input = gr.Checkbox(label="Verloren?")
188
+ with gr.Accordion("Optionen für Handspiele", open=False):
189
+ hand_input = gr.Checkbox(label="Handspiel")
190
+ schneider_angesagt_input = gr.Checkbox(label="Schneider angesagt")
191
+ schwarz_angesagt_input = gr.Checkbox(label="Schwarz angesagt")
192
+ offen_input = gr.Checkbox(label="Offen / Ouvert")
193
+
194
+ # --- Container for Ramsch Game Inputs (hidden by default) ---
195
+ with gr.Group(visible=False) as ramsch_spiel_group:
196
+ gr.Markdown("#### Ramsch-Spiel")
197
+ ramsch_verlierer_input = gr.Dropdown(SPIELER, label="Verlierer")
198
+ ramsch_punkte_input = gr.Number(label="Augen des Verlierers", value=0, precision=0)
199
+ ramsch_geschoben_input = gr.Dropdown(
200
+ choices=[("Keinmal (Standard)", 0), ("1 mal", 1), ("2 mal", 2), ("3 mal", 3)],
201
+ value=0,
202
+ label="Wie oft wurde der Skat geschoben?"
203
+ )
204
 
205
  with gr.Row():
206
  speichere_spiel = gr.Button("Speichere Spiel", variant="primary", scale=2)
 
219
  wrap=True
220
  )
221
 
222
+ # --- Function to dynamically show/hide input sections ---
223
+ def toggle_spielart_inputs(spielart):
224
+ if spielart == "Ramsch":
225
+ return {
226
+ standard_spiel_group: gr.update(visible=False),
227
+ ramsch_spiel_group: gr.update(visible=True)
228
+ }
229
+ else:
230
+ return {
231
+ standard_spiel_group: gr.update(visible=True),
232
+ ramsch_spiel_group: gr.update(visible=False)
233
+ }
234
+
235
+ # --- Event Handlers ---
236
+
237
+ # Link the dropdown change to the visibility function
238
+ spielart_input.change(
239
+ fn=toggle_spielart_inputs,
240
+ inputs=spielart_input,
241
+ outputs=[standard_spiel_group, ramsch_spiel_group]
242
+ )
243
+
244
+ # Consolidate all possible inputs for the click handler
245
+ all_inputs = [
246
+ turnier_output,
247
+ # Standard game inputs
248
  spieler_input, spielart_input, spitzen_input,
249
  hand_input, schneider_input, schwarz_input,
250
  schneider_angesagt_input, schwarz_angesagt_input, offen_input,
251
+ verloren_input,
252
+ # Ramsch game inputs
253
+ ramsch_verlierer_input, ramsch_punkte_input, ramsch_geschoben_input
254
  ]
255
 
256
  speichere_spiel.click(
257
  fn=spiel_hinzufuegen,
258
+ inputs=all_inputs,
259
  outputs=[totals_output, turnier_output]
260
  )
261
 
 
265
  outputs=[totals_output, turnier_output]
266
  )
267
 
 
268
  save_to_hf_button.click(
269
  fn=save_turnier_to_hf,
270
  inputs=[turnier_output],
 
272
  )
273
 
274
  if __name__ == "__main__":
275
+ demo.launch(share=True)