kaggle-environments 1.23.3__py3-none-any.whl → 1.23.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kaggle-environments might be problematic. Click here for more details.
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/repeated_poker.js +2 -2
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/components/getRepeatedPokerStateForStep.js +41 -67
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_1.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_10.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_100.svg +48 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_25.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/images/poker_chip_5.svg +22 -0
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/visualizer/default/src/repeated_poker_renderer.js +557 -332
- kaggle_environments/envs/werewolf/README.md +190 -0
- kaggle_environments/envs/werewolf/harness/__init__.py +0 -0
- kaggle_environments/envs/werewolf/harness/base.py +767 -0
- kaggle_environments/envs/werewolf/harness/litellm_models.yaml +51 -0
- kaggle_environments/envs/werewolf/harness/test_base.py +35 -0
- kaggle_environments/envs/werewolf/runner.py +146 -0
- kaggle_environments/envs/werewolf/scripts/__init__.py +0 -0
- kaggle_environments/envs/werewolf/scripts/add_audio.py +425 -0
- kaggle_environments/envs/werewolf/scripts/configs/audio/standard.yaml +24 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/block_basic.yaml +102 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/comprehensive.yaml +100 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_DisableDoctorSelfSave_DisableDoctorConsecutiveSave_large.yaml +104 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_large.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/roundrobin_discussion_small.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_DisableDoctorConsecutiveSave.yaml +104 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam_NightEliminationNoReveal_DayExileNoReveal.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_DisableDoctorSelfSave_SeerRevealTeam_NightEliminationRevealTeam_DayExileRevealTeam.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_disable_doctor_self_save.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_no_tie_exile.yaml +103 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/rule_experiment/standard_parallel_voting_roundbiddiscussion.yaml +105 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/run_config.yaml +58 -0
- kaggle_environments/envs/werewolf/scripts/configs/run/vertex_api_example_config.yaml +115 -0
- kaggle_environments/envs/werewolf/scripts/measure_cost.py +251 -0
- kaggle_environments/envs/werewolf/scripts/plot_existing_trajectories.py +135 -0
- kaggle_environments/envs/werewolf/scripts/rerender_html.py +87 -0
- kaggle_environments/envs/werewolf/scripts/run.py +93 -0
- kaggle_environments/envs/werewolf/scripts/run_block.py +237 -0
- kaggle_environments/envs/werewolf/scripts/run_pairwise_matrix.py +222 -0
- kaggle_environments/envs/werewolf/scripts/self_play.py +196 -0
- kaggle_environments/envs/werewolf/scripts/utils.py +47 -0
- {kaggle_environments-1.23.3.dist-info → kaggle_environments-1.23.5.dist-info}/METADATA +1 -1
- {kaggle_environments-1.23.3.dist-info → kaggle_environments-1.23.5.dist-info}/RECORD +46 -8
- {kaggle_environments-1.23.3.dist-info → kaggle_environments-1.23.5.dist-info}/WHEEL +0 -0
- {kaggle_environments-1.23.3.dist-info → kaggle_environments-1.23.5.dist-info}/entry_points.txt +0 -0
- {kaggle_environments-1.23.3.dist-info → kaggle_environments-1.23.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,22 +1,37 @@
|
|
|
1
1
|
import { getPokerStateForStep } from "./components/getRepeatedPokerStateForStep";
|
|
2
2
|
import { acpcCardToDisplay, suitSVGs } from "./components/utils";
|
|
3
|
+
import poker_chip_1 from "./images/poker_chip_1.svg";
|
|
4
|
+
import poker_chip_5 from "./images/poker_chip_5.svg";
|
|
5
|
+
import poker_chip_10 from "./images/poker_chip_10.svg";
|
|
6
|
+
import poker_chip_25 from "./images/poker_chip_25.svg";
|
|
7
|
+
import poker_chip_100 from "./images/poker_chip_100.svg";
|
|
3
8
|
|
|
4
9
|
export function renderer(options) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
const chipImages = {
|
|
11
|
+
1: poker_chip_1,
|
|
12
|
+
5: poker_chip_5,
|
|
13
|
+
10: poker_chip_10,
|
|
14
|
+
25: poker_chip_25,
|
|
15
|
+
100: poker_chip_100
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const elements = {
|
|
19
|
+
gameLayout: null,
|
|
20
|
+
pokerTableContainer: null,
|
|
21
|
+
pokerTable: null,
|
|
22
|
+
communityCardsContainer: null,
|
|
23
|
+
potDisplay: null,
|
|
24
|
+
playersContainer: null,
|
|
25
|
+
playerCardAreas: [],
|
|
26
|
+
playerInfoAreas: [],
|
|
27
|
+
playerThumbnails: [],
|
|
28
|
+
dealerButton: null,
|
|
29
|
+
chipStacks: [],
|
|
30
|
+
diagnosticHeader: null,
|
|
31
|
+
stepCounter: null
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const css = `
|
|
20
35
|
@font-face {
|
|
21
36
|
font-family: 'Zeitung Pro';
|
|
22
37
|
src:
|
|
@@ -44,12 +59,12 @@ export function renderer(options) {
|
|
|
44
59
|
|
|
45
60
|
.poker-renderer-host {
|
|
46
61
|
width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
|
|
47
|
-
font-family: 'Zeitung Pro', sans-serif; background-color: #
|
|
62
|
+
font-family: 'Zeitung Pro', sans-serif; background-color: #28303F; color: #fff;
|
|
48
63
|
overflow: hidden; box-sizing: border-box; position: relative;
|
|
49
64
|
}
|
|
50
65
|
.poker-game-layout {
|
|
51
66
|
width: 1000px;
|
|
52
|
-
height:
|
|
67
|
+
height: 900px;
|
|
53
68
|
display: flex;
|
|
54
69
|
align-items: center;
|
|
55
70
|
justify-content: center;
|
|
@@ -74,6 +89,19 @@ export function renderer(options) {
|
|
|
74
89
|
align-items: center;
|
|
75
90
|
justify-content: center;
|
|
76
91
|
margin: 0;
|
|
92
|
+
box-shadow: 0 8px 12px 6px rgba(0, 0, 0, 0.15), 0 4px 4px 0 rgba(0, 0, 0, 0.30);
|
|
93
|
+
}
|
|
94
|
+
.muck-line {
|
|
95
|
+
position: absolute;
|
|
96
|
+
width: 780px;
|
|
97
|
+
height: 300px;
|
|
98
|
+
border: 1px solid #9AA0A6;
|
|
99
|
+
border-radius: 240px;
|
|
100
|
+
pointer-events: none;
|
|
101
|
+
z-index: 1;
|
|
102
|
+
display: flex;
|
|
103
|
+
align-items: center;
|
|
104
|
+
justify-content: center;
|
|
77
105
|
}
|
|
78
106
|
.players-container {
|
|
79
107
|
position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 10;
|
|
@@ -85,51 +113,91 @@ export function renderer(options) {
|
|
|
85
113
|
display: flex;
|
|
86
114
|
flex-direction: column;
|
|
87
115
|
}
|
|
88
|
-
.player-container-0 {
|
|
89
|
-
.player-container-1 {
|
|
90
|
-
.player-area
|
|
116
|
+
.player-container-0 { top: 0; }
|
|
117
|
+
.player-container-1 { bottom: 0; flex-direction: column-reverse; }
|
|
118
|
+
.player-card-area {
|
|
119
|
+
color: white; text-align: center;
|
|
120
|
+
display: flex; justify-content: left; align-items: left;
|
|
121
|
+
pointer-events: auto;
|
|
122
|
+
flex: 1;
|
|
123
|
+
}
|
|
124
|
+
.stack-cards-wrapper {
|
|
91
125
|
display: flex;
|
|
92
|
-
|
|
126
|
+
flex-direction: row;
|
|
93
127
|
align-items: center;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
margin:
|
|
97
|
-
|
|
98
|
-
min-height: 100px; pointer-events: auto;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
gap: 16px;
|
|
130
|
+
margin: 12px;
|
|
131
|
+
width: 100%;
|
|
99
132
|
}
|
|
100
133
|
.player-info-area {
|
|
101
134
|
color: white;
|
|
102
|
-
|
|
135
|
+
width: auto;
|
|
136
|
+
min-width: 200px;
|
|
103
137
|
pointer-events: auto;
|
|
104
138
|
display: flex;
|
|
105
139
|
flex-direction: column;
|
|
106
|
-
justify-content:
|
|
107
|
-
align-items:
|
|
108
|
-
margin
|
|
140
|
+
justify-content: center;
|
|
141
|
+
align-items: center;
|
|
142
|
+
margin: 20px auto;
|
|
143
|
+
padding: 20px;
|
|
144
|
+
background-color: rgba(32, 33, 36, 0.70);;
|
|
145
|
+
border-radius: 16px;
|
|
146
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
|
147
|
+
border: 2px solid transparent;
|
|
148
|
+
transition: border-color 0.3s ease, box-shadow 0.3s ease;
|
|
149
|
+
}
|
|
150
|
+
.player-info-area.active-player {
|
|
151
|
+
border-color: #20BEFF;
|
|
152
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), 0 0 20px rgba(32, 190, 255, 0.5);
|
|
153
|
+
}
|
|
154
|
+
.player-info-area.winner-player {
|
|
155
|
+
border-color: #FFEB70;
|
|
156
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), 0 0 20px rgba(255, 235, 112, 0.6);
|
|
109
157
|
}
|
|
110
158
|
.player-container-0 .player-info-area { flex-direction: column-reverse; }
|
|
159
|
+
.player-name-wrapper {
|
|
160
|
+
display: flex;
|
|
161
|
+
align-items: center;
|
|
162
|
+
justify-content: center;
|
|
163
|
+
gap: 16px;
|
|
164
|
+
margin: 0 60px;
|
|
165
|
+
padding: 10px 0;
|
|
166
|
+
}
|
|
167
|
+
.player-thumbnail {
|
|
168
|
+
width: 48px;
|
|
169
|
+
height: 48px;
|
|
170
|
+
border-radius: 50%;
|
|
171
|
+
object-fit: cover;
|
|
172
|
+
background-color: #ffffff;
|
|
173
|
+
flex-shrink: 0;
|
|
174
|
+
padding: 6px;
|
|
175
|
+
}
|
|
111
176
|
.player-name {
|
|
112
|
-
font-size:
|
|
177
|
+
font-size: 24px; font-weight: 600;
|
|
113
178
|
white-space: nowrap;
|
|
114
179
|
overflow: hidden;
|
|
115
180
|
text-overflow: ellipsis;
|
|
116
181
|
color: white;
|
|
117
|
-
text-align:
|
|
118
|
-
padding: 10px 0;
|
|
119
|
-
margin: 0 60px;
|
|
182
|
+
text-align: center;
|
|
120
183
|
}
|
|
121
184
|
.player-name.winner { color: #FFEB70; }
|
|
122
|
-
.player-
|
|
123
|
-
.player-
|
|
185
|
+
.player-name.current-turn { color: #20BEFF; }
|
|
186
|
+
.player-stack { font-size: 20px; font-weight: 600; color: #ffffff; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; }
|
|
187
|
+
.player-cards-container { min-height: 80px; display: flex; justify-content: center; align-items:center;}
|
|
124
188
|
.card {
|
|
125
189
|
display: flex; flex-direction: column; justify-content: space-between; align-items: center;
|
|
126
|
-
width:
|
|
190
|
+
width: 44px; height: 70px; border: 2px solid #202124; border-radius: 8px;
|
|
127
191
|
background-color: white; color: black; font-weight: bold; text-align: center; overflow: hidden; position: relative;
|
|
128
192
|
padding: 6px;
|
|
129
193
|
box-shadow: 0 6px 10px 4px rgba(0, 0, 0, 0.15), 0 2px 3px 0 rgba(0, 0, 0, 0.30);
|
|
130
194
|
}
|
|
131
|
-
.card-rank { font-family: 'Inter' sans-serif; font-size:
|
|
132
|
-
.card-suit { width:
|
|
195
|
+
.card-rank { font-family: 'Inter' sans-serif; font-size: 32px; line-height: 1; display: block; align-self: flex-start; }
|
|
196
|
+
.card-suit { width: 36px; height: 36px; display: block; margin-bottom: 2px; }
|
|
197
|
+
.player-cards-container .card { width: 38px; height: 60px; border-radius: 6px; }
|
|
198
|
+
.player-cards-container .card:nth-child(2) { transform: rotate(20deg); margin-top: 14px; margin-left: -6px; }
|
|
199
|
+
.player-cards-container .card-rank { font-size: 26px; }
|
|
200
|
+
.player-cards-container .card-suit { width: 28px; height: 28px; }
|
|
133
201
|
.card-suit svg { width: 100%; height: 100%; }
|
|
134
202
|
.card-red .card-rank { color: #B3261E; }
|
|
135
203
|
.card-red .card-suit svg { fill: #B3261E; }
|
|
@@ -154,24 +222,30 @@ export function renderer(options) {
|
|
|
154
222
|
.card-empty .card-rank, .card-empty .card-suit { display: none; }
|
|
155
223
|
.community-cards-area { text-align: center; z-index: 10; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
|
|
156
224
|
.community-cards-container { min-height: 75px; display: flex; justify-content: center; align-items:center; margin-bottom: 0.5rem; gap: 8px; }
|
|
157
|
-
.pot-display { font-size: 30px; font-weight: bold; color: #ffffff; margin-bottom:
|
|
225
|
+
.pot-display { font-size: 30px; font-weight: bold; color: #ffffff; margin-bottom: 10px; }
|
|
158
226
|
.bet-display {
|
|
159
|
-
display: inline-block; padding: 10px 20px; border-radius:
|
|
160
|
-
background-color: #
|
|
161
|
-
font-family: 'Inter' sans-serif; font-size:
|
|
227
|
+
display: inline-block; padding: 10px 20px; border-radius: 30px;
|
|
228
|
+
background-color: #ffffff; color: black;
|
|
229
|
+
font-family: 'Inter' sans-serif; font-size: 20px; font-weight: 600;
|
|
162
230
|
text-align: center;
|
|
163
|
-
height:
|
|
164
|
-
|
|
231
|
+
height: 20pxrem; line-height: 20px;
|
|
232
|
+
width: 150px;
|
|
233
|
+
height: 20px;
|
|
165
234
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
166
235
|
}
|
|
167
236
|
.blind-indicator { font-size: 0.7rem; color: #a0aec0; margin-top: 3px; }
|
|
168
237
|
.dealer-button {
|
|
169
238
|
width: 36px; height: 36px; background-color: #f0f0f0; color: #333; border-radius: 50%;
|
|
170
|
-
text-align: center;
|
|
171
|
-
|
|
239
|
+
text-align: center; font-weight: bold; font-size: 28px; position: absolute;
|
|
240
|
+
padding-left: 1px;
|
|
241
|
+
line-height: 33px;
|
|
242
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.3); z-index: 15; pointer-events: auto;
|
|
243
|
+
border: 2px solid black;
|
|
244
|
+
outline: 2px solid #20BEFF;
|
|
245
|
+
left: 320px
|
|
172
246
|
}
|
|
173
|
-
.dealer-button.dealer-player0 {
|
|
174
|
-
.dealer-button.dealer-player1 {
|
|
247
|
+
.dealer-button.dealer-player0 { top: 170px; }
|
|
248
|
+
.dealer-button.dealer-player1 { bottom: 170px; }
|
|
175
249
|
.step-counter {
|
|
176
250
|
position: absolute; top: 12px; right: 12px; z-index: 20;
|
|
177
251
|
background-color: rgba(60, 64, 67, 0.9); color: #ffffff;
|
|
@@ -179,321 +253,472 @@ export function renderer(options) {
|
|
|
179
253
|
font-size: 14px; font-weight: 600;
|
|
180
254
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
181
255
|
}
|
|
256
|
+
.chip-stack {
|
|
257
|
+
position: absolute;
|
|
258
|
+
display: flex;
|
|
259
|
+
flex-direction: row;
|
|
260
|
+
align-items: center;
|
|
261
|
+
gap: 12px;
|
|
262
|
+
z-index: 12;
|
|
263
|
+
pointer-events: none;
|
|
264
|
+
left: 50%;
|
|
265
|
+
transform: translateX(-50%);
|
|
266
|
+
}
|
|
267
|
+
.chip-stack.chip-stack-player0 {
|
|
268
|
+
top: 60px;
|
|
269
|
+
}
|
|
270
|
+
.chip-stack.chip-stack-player1 {
|
|
271
|
+
bottom: 60px;
|
|
272
|
+
}
|
|
273
|
+
.chip-stack-chips {
|
|
274
|
+
display: flex;
|
|
275
|
+
flex-direction: row-reverse;
|
|
276
|
+
align-items: flex-end;
|
|
277
|
+
justify-content: center;
|
|
278
|
+
gap: 8px;
|
|
279
|
+
position: relative;
|
|
280
|
+
}
|
|
281
|
+
.chip-denomination-stack {
|
|
282
|
+
display: flex;
|
|
283
|
+
flex-direction: column-reverse;
|
|
284
|
+
align-items: center;
|
|
285
|
+
position: relative;
|
|
286
|
+
}
|
|
287
|
+
.chip {
|
|
288
|
+
width: 40px;
|
|
289
|
+
height: 40px;
|
|
290
|
+
position: relative;
|
|
291
|
+
margin-bottom: -34px;
|
|
292
|
+
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
|
|
293
|
+
}
|
|
294
|
+
.chip:first-child {
|
|
295
|
+
margin-bottom: 0;
|
|
296
|
+
}
|
|
297
|
+
.chip img {
|
|
298
|
+
width: 100%;
|
|
299
|
+
height: 100%;
|
|
300
|
+
display: block;
|
|
301
|
+
}
|
|
302
|
+
.chip-stack-label {
|
|
303
|
+
color: #FFFFFF;
|
|
304
|
+
font-size: 18px;
|
|
305
|
+
font-weight: bold;
|
|
306
|
+
white-space: nowrap;
|
|
307
|
+
}
|
|
182
308
|
`;
|
|
183
309
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
window.__poker_styles_injected = true;
|
|
310
|
+
function _injectStyles(passedOptions) {
|
|
311
|
+
if (typeof document === 'undefined' || window.__poker_styles_injected) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const style = document.createElement('style');
|
|
315
|
+
style.textContent = css;
|
|
316
|
+
const parentForStyles =
|
|
317
|
+
passedOptions && passedOptions.parent ? passedOptions.parent.ownerDocument.head : document.head;
|
|
318
|
+
if (parentForStyles && !parentForStyles.querySelector('style[data-poker-renderer-styles]')) {
|
|
319
|
+
style.setAttribute('data-poker-renderer-styles', 'true');
|
|
320
|
+
parentForStyles.appendChild(style);
|
|
197
321
|
}
|
|
322
|
+
window.__poker_styles_injected = true;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function createCardElement(cardStr, isHidden = false) {
|
|
326
|
+
const cardDiv = document.createElement('div');
|
|
327
|
+
cardDiv.classList.add('card');
|
|
328
|
+
if (isHidden || !cardStr || cardStr === '?' || cardStr === '??') {
|
|
329
|
+
cardDiv.classList.add('card-back');
|
|
330
|
+
} else {
|
|
331
|
+
const { rank, suit } = acpcCardToDisplay(cardStr);
|
|
332
|
+
const rankSpan = document.createElement('span');
|
|
333
|
+
rankSpan.classList.add('card-rank');
|
|
334
|
+
rankSpan.textContent = rank;
|
|
335
|
+
cardDiv.appendChild(rankSpan);
|
|
336
|
+
|
|
337
|
+
const suitSpan = document.createElement('span');
|
|
338
|
+
suitSpan.classList.add('card-suit');
|
|
339
|
+
|
|
340
|
+
if (suitSVGs[suit]) {
|
|
341
|
+
suitSpan.innerHTML = suitSVGs[suit];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
cardDiv.appendChild(suitSpan);
|
|
345
|
+
|
|
346
|
+
if (suit === 'hearts') cardDiv.classList.add('card-red');
|
|
347
|
+
else if (suit === 'spades') cardDiv.classList.add('card-black');
|
|
348
|
+
else if (suit === 'diamonds') cardDiv.classList.add('card-blue');
|
|
349
|
+
else if (suit === 'clubs') cardDiv.classList.add('card-green');
|
|
350
|
+
}
|
|
351
|
+
return cardDiv;
|
|
352
|
+
}
|
|
198
353
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
} else {
|
|
205
|
-
const { rank, suit } = acpcCardToDisplay(cardStr);
|
|
206
|
-
const rankSpan = document.createElement('span');
|
|
207
|
-
rankSpan.classList.add('card-rank');
|
|
208
|
-
rankSpan.textContent = rank;
|
|
209
|
-
cardDiv.appendChild(rankSpan);
|
|
354
|
+
function updateChipStack(chipStackElement, betAmount) {
|
|
355
|
+
if (betAmount <= 0) {
|
|
356
|
+
chipStackElement.style.display = 'none';
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
210
359
|
|
|
211
|
-
|
|
212
|
-
|
|
360
|
+
chipStackElement.style.display = 'flex';
|
|
361
|
+
const chipsContainer = chipStackElement.querySelector('.chip-stack-chips');
|
|
362
|
+
const labelElement = chipStackElement.querySelector('.chip-stack-label');
|
|
213
363
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
364
|
+
chipsContainer.innerHTML = '';
|
|
365
|
+
labelElement.textContent = betAmount;
|
|
217
366
|
|
|
218
|
-
|
|
367
|
+
// Break down bet into denominations (100, 25, 10, 5, 1)
|
|
368
|
+
const denominations = [100, 25, 10, 5, 1];
|
|
369
|
+
let remaining = betAmount;
|
|
370
|
+
const chipCounts = [];
|
|
219
371
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// --- Board Parsing and Rendering ---
|
|
229
|
-
function _ensurePokerTableElements(parentElement, passedOptions) {
|
|
230
|
-
if (!parentElement) return false;
|
|
231
|
-
parentElement.innerHTML = '';
|
|
232
|
-
parentElement.classList.add('poker-renderer-host');
|
|
233
|
-
|
|
234
|
-
elements.diagnosticHeader = document.createElement('h1');
|
|
235
|
-
elements.diagnosticHeader.id = 'poker-renderer-diagnostic-header';
|
|
236
|
-
elements.diagnosticHeader.textContent = 'Poker Table Initialized (Live Data)';
|
|
237
|
-
elements.diagnosticHeader.style.cssText =
|
|
238
|
-
'color: lime; background-color: black; padding: 5px; font-size: 12px; position: absolute; top: 0px; left: 0px; z-index: 10001; display: none;'; // Hidden by default
|
|
239
|
-
parentElement.appendChild(elements.diagnosticHeader);
|
|
240
|
-
|
|
241
|
-
elements.gameLayout = document.createElement('div');
|
|
242
|
-
elements.gameLayout.className = 'poker-game-layout';
|
|
243
|
-
parentElement.appendChild(elements.gameLayout);
|
|
244
|
-
|
|
245
|
-
elements.pokerTableContainer = document.createElement('div');
|
|
246
|
-
elements.pokerTableContainer.className = 'poker-table-container';
|
|
247
|
-
elements.gameLayout.appendChild(elements.pokerTableContainer);
|
|
248
|
-
|
|
249
|
-
elements.playersContainer = document.createElement('div');
|
|
250
|
-
elements.playersContainer.className = 'players-container';
|
|
251
|
-
elements.gameLayout.appendChild(elements.playersContainer);
|
|
252
|
-
|
|
253
|
-
elements.pokerTable = document.createElement('div');
|
|
254
|
-
elements.pokerTable.className = 'poker-table';
|
|
255
|
-
elements.pokerTableContainer.appendChild(elements.pokerTable);
|
|
256
|
-
|
|
257
|
-
const communityArea = document.createElement('div');
|
|
258
|
-
communityArea.className = 'community-cards-area';
|
|
259
|
-
elements.pokerTable.appendChild(communityArea);
|
|
260
|
-
|
|
261
|
-
elements.potDisplay = document.createElement('div');
|
|
262
|
-
elements.potDisplay.className = 'pot-display';
|
|
263
|
-
communityArea.appendChild(elements.potDisplay);
|
|
264
|
-
|
|
265
|
-
elements.communityCardsContainer = document.createElement('div');
|
|
266
|
-
elements.communityCardsContainer.className = 'community-cards-container';
|
|
267
|
-
communityArea.appendChild(elements.communityCardsContainer);
|
|
268
|
-
|
|
269
|
-
elements.playerContainers = [];
|
|
270
|
-
elements.playerCardAreas = [];
|
|
271
|
-
elements.playerInfoAreas = [];
|
|
272
|
-
elements.playerNames = [];
|
|
273
|
-
|
|
274
|
-
for (let i = 0; i < 2; i++) {
|
|
275
|
-
// Create player container that groups all player elements
|
|
276
|
-
const playerContainer = document.createElement('div');
|
|
277
|
-
playerContainer.className = `player-container player-container-${i}`;
|
|
278
|
-
elements.playersContainer.appendChild(playerContainer);
|
|
279
|
-
elements.playerContainers.push(playerContainer);
|
|
280
|
-
|
|
281
|
-
// Player name
|
|
282
|
-
const playerName = document.createElement('div');
|
|
283
|
-
playerName.className = `player-name`;
|
|
284
|
-
playerName.textContent = `Player ${i}`;
|
|
285
|
-
playerContainer.appendChild(playerName);
|
|
286
|
-
elements.playerNames.push(playerName);
|
|
287
|
-
|
|
288
|
-
// Create wrapper for card and info areas
|
|
289
|
-
const playerAreaWrapper = document.createElement('div');
|
|
290
|
-
playerAreaWrapper.className = 'player-area-wrapper';
|
|
291
|
-
playerContainer.appendChild(playerAreaWrapper);
|
|
292
|
-
|
|
293
|
-
// Card area (left side)
|
|
294
|
-
const playerCardArea = document.createElement('div');
|
|
295
|
-
playerCardArea.className = `player-card-area`;
|
|
296
|
-
playerCardArea.innerHTML = `
|
|
297
|
-
<div class="player-cards-container"></div>
|
|
298
|
-
`;
|
|
299
|
-
playerAreaWrapper.appendChild(playerCardArea);
|
|
300
|
-
elements.playerCardAreas.push(playerCardArea);
|
|
301
|
-
|
|
302
|
-
// TODO: Render chip stack
|
|
303
|
-
// Info area (right side)
|
|
304
|
-
const playerInfoArea = document.createElement('div');
|
|
305
|
-
playerInfoArea.className = `player-info-area`;
|
|
306
|
-
playerInfoArea.innerHTML = `
|
|
307
|
-
<div class="player-stack">
|
|
308
|
-
<span class="player-stack-value">0</span>
|
|
309
|
-
</div>
|
|
310
|
-
<div class="bet-display" style="display:none;">Bet : 0</div>
|
|
311
|
-
`;
|
|
312
|
-
playerAreaWrapper.appendChild(playerInfoArea);
|
|
313
|
-
elements.playerInfoAreas.push(playerInfoArea);
|
|
314
|
-
}
|
|
372
|
+
for (const denom of denominations) {
|
|
373
|
+
const count = Math.floor(remaining / denom);
|
|
374
|
+
if (count > 0) {
|
|
375
|
+
chipCounts.push({ denom, count: Math.min(count, 5) }); // Max 5 of each denomination
|
|
376
|
+
remaining -= count * denom;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
315
379
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
380
|
+
// Render chips separated by denomination (highest to lowest, left to right)
|
|
381
|
+
chipCounts.forEach(({ denom, count }) => {
|
|
382
|
+
const denomStack = document.createElement('div');
|
|
383
|
+
denomStack.className = 'chip-denomination-stack';
|
|
384
|
+
|
|
385
|
+
for (let i = 0; i < count; i++) {
|
|
386
|
+
const chip = document.createElement('div');
|
|
387
|
+
chip.className = 'chip';
|
|
388
|
+
const img = document.createElement('img');
|
|
389
|
+
img.src = chipImages[denom];
|
|
390
|
+
img.alt = `${denom} chip`;
|
|
391
|
+
chip.appendChild(img);
|
|
392
|
+
denomStack.appendChild(chip);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
chipsContainer.appendChild(denomStack);
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// --- Board Parsing and Rendering ---
|
|
400
|
+
function _ensurePokerTableElements(parentElement, passedOptions) {
|
|
401
|
+
if (!parentElement) return false;
|
|
402
|
+
parentElement.innerHTML = '';
|
|
403
|
+
parentElement.classList.add('poker-renderer-host');
|
|
404
|
+
|
|
405
|
+
elements.diagnosticHeader = document.createElement('h1');
|
|
406
|
+
elements.diagnosticHeader.id = 'poker-renderer-diagnostic-header';
|
|
407
|
+
elements.diagnosticHeader.textContent = 'Poker Table Initialized (Live Data)';
|
|
408
|
+
elements.diagnosticHeader.style.cssText =
|
|
409
|
+
'color: lime; background-color: black; padding: 5px; font-size: 12px; position: absolute; top: 0px; left: 0px; z-index: 10001; display: none;'; // Hidden by default
|
|
410
|
+
parentElement.appendChild(elements.diagnosticHeader);
|
|
411
|
+
|
|
412
|
+
elements.gameLayout = document.createElement('div');
|
|
413
|
+
elements.gameLayout.className = 'poker-game-layout';
|
|
414
|
+
parentElement.appendChild(elements.gameLayout);
|
|
415
|
+
|
|
416
|
+
elements.pokerTableContainer = document.createElement('div');
|
|
417
|
+
elements.pokerTableContainer.className = 'poker-table-container';
|
|
418
|
+
elements.gameLayout.appendChild(elements.pokerTableContainer);
|
|
419
|
+
|
|
420
|
+
elements.playersContainer = document.createElement('div');
|
|
421
|
+
elements.playersContainer.className = 'players-container';
|
|
422
|
+
elements.gameLayout.appendChild(elements.playersContainer);
|
|
423
|
+
|
|
424
|
+
elements.pokerTable = document.createElement('div');
|
|
425
|
+
elements.pokerTable.className = 'poker-table';
|
|
426
|
+
elements.pokerTableContainer.appendChild(elements.pokerTable);
|
|
427
|
+
|
|
428
|
+
const muckLine = document.createElement('div');
|
|
429
|
+
muckLine.className = 'muck-line';
|
|
430
|
+
elements.pokerTable.appendChild(muckLine);
|
|
431
|
+
|
|
432
|
+
// Create chip stacks for each player inside the table
|
|
433
|
+
elements.chipStacks = [];
|
|
434
|
+
for (let i = 0; i < 2; i++) {
|
|
435
|
+
const chipStack = document.createElement('div');
|
|
436
|
+
chipStack.className = `chip-stack chip-stack-player${i}`;
|
|
437
|
+
chipStack.style.display = 'none';
|
|
438
|
+
chipStack.innerHTML = `
|
|
439
|
+
<div class="chip-stack-chips"></div>
|
|
440
|
+
<div class="chip-stack-label">0</div>
|
|
441
|
+
`;
|
|
442
|
+
elements.pokerTable.appendChild(chipStack);
|
|
443
|
+
elements.chipStacks.push(chipStack);
|
|
444
|
+
}
|
|
346
445
|
|
|
347
|
-
|
|
446
|
+
const communityArea = document.createElement('div');
|
|
447
|
+
communityArea.className = 'community-cards-area';
|
|
448
|
+
elements.pokerTable.appendChild(communityArea);
|
|
449
|
+
|
|
450
|
+
elements.potDisplay = document.createElement('div');
|
|
451
|
+
elements.potDisplay.className = 'pot-display';
|
|
452
|
+
communityArea.appendChild(elements.potDisplay);
|
|
453
|
+
|
|
454
|
+
elements.communityCardsContainer = document.createElement('div');
|
|
455
|
+
elements.communityCardsContainer.className = 'community-cards-container';
|
|
456
|
+
communityArea.appendChild(elements.communityCardsContainer);
|
|
457
|
+
|
|
458
|
+
elements.playerContainers = [];
|
|
459
|
+
elements.playerCardAreas = [];
|
|
460
|
+
elements.playerInfoAreas = [];
|
|
461
|
+
elements.playerNames = [];
|
|
462
|
+
elements.playerThumbnails = [];
|
|
463
|
+
|
|
464
|
+
for (let i = 0; i < 2; i++) {
|
|
465
|
+
// Create player container that groups all player elements
|
|
466
|
+
const playerContainer = document.createElement('div');
|
|
467
|
+
playerContainer.className = `player-container player-container-${i}`;
|
|
468
|
+
elements.playersContainer.appendChild(playerContainer);
|
|
469
|
+
elements.playerContainers.push(playerContainer);
|
|
470
|
+
|
|
471
|
+
// Player name wrapper with thumbnail
|
|
472
|
+
const playerNameWrapper = document.createElement('div');
|
|
473
|
+
playerNameWrapper.className = `player-name-wrapper`;
|
|
474
|
+
playerContainer.appendChild(playerNameWrapper);
|
|
475
|
+
|
|
476
|
+
// Player thumbnail
|
|
477
|
+
const playerThumbnail = document.createElement('img');
|
|
478
|
+
playerThumbnail.className = `player-thumbnail`;
|
|
479
|
+
playerThumbnail.style.display = 'none'; // Hidden by default
|
|
480
|
+
playerNameWrapper.appendChild(playerThumbnail);
|
|
481
|
+
elements.playerThumbnails.push(playerThumbnail);
|
|
482
|
+
|
|
483
|
+
// Player name
|
|
484
|
+
const playerName = document.createElement('div');
|
|
485
|
+
playerName.className = `player-name`;
|
|
486
|
+
playerName.textContent = `Player ${i}`;
|
|
487
|
+
playerNameWrapper.appendChild(playerName);
|
|
488
|
+
elements.playerNames.push(playerName);
|
|
489
|
+
|
|
490
|
+
// Info area containing bet, cards, and stack
|
|
491
|
+
const playerInfoArea = document.createElement('div');
|
|
492
|
+
playerInfoArea.className = `player-info-area`;
|
|
493
|
+
playerInfoArea.innerHTML = `
|
|
494
|
+
<div class="bet-display">Standby</div>
|
|
495
|
+
<div class="stack-cards-wrapper">
|
|
496
|
+
<div class="player-card-area">
|
|
497
|
+
<div class="player-cards-container"></div>
|
|
498
|
+
</div>
|
|
499
|
+
<div class="player-stack">
|
|
500
|
+
<span class="player-stack-value">0</span>
|
|
501
|
+
</div>
|
|
502
|
+
</div>
|
|
503
|
+
`;
|
|
504
|
+
playerContainer.appendChild(playerInfoArea);
|
|
505
|
+
elements.playerInfoAreas.push(playerInfoArea);
|
|
506
|
+
|
|
507
|
+
// Get reference to card area (already in DOM)
|
|
508
|
+
const playerCardArea = playerInfoArea.querySelector('.player-card-area');
|
|
509
|
+
elements.playerCardAreas.push(playerCardArea);
|
|
348
510
|
}
|
|
349
511
|
|
|
350
|
-
|
|
351
|
-
|
|
512
|
+
elements.dealerButton = document.createElement('div');
|
|
513
|
+
elements.dealerButton.className = 'dealer-button';
|
|
514
|
+
elements.dealerButton.textContent = 'D';
|
|
515
|
+
elements.dealerButton.style.display = 'none';
|
|
516
|
+
elements.playersContainer.appendChild(elements.dealerButton);
|
|
517
|
+
|
|
518
|
+
elements.stepCounter = document.createElement('div');
|
|
519
|
+
elements.stepCounter.className = 'step-counter';
|
|
520
|
+
elements.stepCounter.textContent = 'Standby';
|
|
521
|
+
elements.gameLayout.appendChild(elements.stepCounter);
|
|
522
|
+
return true;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// --- State Parsing ---
|
|
526
|
+
function _parseKagglePokerState(options) {
|
|
527
|
+
const { environment, step } = options;
|
|
528
|
+
const numPlayers = 2;
|
|
529
|
+
|
|
530
|
+
// --- Default State ---
|
|
531
|
+
const defaultStateUiData = {
|
|
532
|
+
players: [],
|
|
533
|
+
communityCards: [],
|
|
534
|
+
pot: 0,
|
|
535
|
+
isTerminal: false,
|
|
536
|
+
};
|
|
352
537
|
|
|
353
|
-
|
|
354
|
-
|
|
538
|
+
// --- Step Validation ---
|
|
539
|
+
if (!environment || !environment.steps || !environment.steps[step] || !environment.info?.stateHistory) {
|
|
540
|
+
return defaultStateUiData;
|
|
541
|
+
}
|
|
355
542
|
|
|
356
|
-
|
|
357
|
-
|
|
543
|
+
return getPokerStateForStep(environment, step);
|
|
544
|
+
}
|
|
358
545
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
const scale = Math.min(scaleX, scaleY);
|
|
546
|
+
function _applyScale(parentElement) {
|
|
547
|
+
if (!parentElement || !elements.gameLayout) return;
|
|
362
548
|
|
|
363
|
-
|
|
364
|
-
|
|
549
|
+
const parentWidth = parentElement.clientWidth;
|
|
550
|
+
const parentHeight = parentElement.clientHeight;
|
|
365
551
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
const { players, communityCards, pot, isTerminal, step } = data;
|
|
552
|
+
const baseWidth = 1000;
|
|
553
|
+
const baseHeight = 1000;
|
|
369
554
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}
|
|
555
|
+
const scaleX = parentWidth / baseWidth;
|
|
556
|
+
const scaleY = parentHeight / baseHeight;
|
|
557
|
+
const scale = Math.min(scaleX, scaleY);
|
|
374
558
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
// elements.diagnosticHeader.textContent = `[${passedOptions.step}] P_TURN:${data.rawObservation.current_player} POT:${data.pot}`;
|
|
378
|
-
// elements.diagnosticHeader.style.display = 'block';
|
|
379
|
-
}
|
|
559
|
+
elements.gameLayout.style.transform = `scale(${scale})`;
|
|
560
|
+
}
|
|
380
561
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const numCommunityCards = 5;
|
|
385
|
-
const numCards = communityCards ? communityCards.length : 0;
|
|
562
|
+
function _renderPokerTableUI(data, passedOptions) {
|
|
563
|
+
if (!elements.pokerTable || !data) return;
|
|
564
|
+
const { players, communityCards, pot, isTerminal, step } = data;
|
|
386
565
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
566
|
+
// Update step counter
|
|
567
|
+
if (elements.stepCounter && step !== undefined) {
|
|
568
|
+
elements.stepCounter.textContent = `Debug Step: ${step}`;
|
|
569
|
+
}
|
|
390
570
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
571
|
+
if (elements.diagnosticHeader && data.rawObservation) {
|
|
572
|
+
// Optional: Show diagnostics for debugging
|
|
573
|
+
// elements.diagnosticHeader.textContent = `[${passedOptions.step}] P_TURN:${data.rawObservation.current_player} POT:${data.pot}`;
|
|
574
|
+
// elements.diagnosticHeader.style.display = 'block';
|
|
575
|
+
}
|
|
395
576
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
577
|
+
elements.communityCardsContainer.innerHTML = '';
|
|
578
|
+
// Always show 5 slots for the river
|
|
579
|
+
// Display cards left to right, with empty slots at the end
|
|
580
|
+
const numCommunityCards = 5;
|
|
581
|
+
const numCards = communityCards ? communityCards.length : 0;
|
|
402
582
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
const playerNameElement = elements.playerNames[index];
|
|
407
|
-
if (playerNameElement) {
|
|
408
|
-
const playerNameText =
|
|
409
|
-
playerData.isTurn && !isTerminal ? `${playerData.name} responding...` : playerData.name;
|
|
410
|
-
playerNameElement.textContent = playerNameText;
|
|
411
|
-
|
|
412
|
-
// Add winner class if player won
|
|
413
|
-
if (playerData.isWinner) {
|
|
414
|
-
playerNameElement.classList.add('winner');
|
|
415
|
-
} else {
|
|
416
|
-
playerNameElement.classList.remove('winner');
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Update card area (left side)
|
|
421
|
-
const playerCardArea = elements.playerCardAreas[index];
|
|
422
|
-
if (playerCardArea) {
|
|
423
|
-
const playerCardsContainer = playerCardArea.querySelector('.player-cards-container');
|
|
424
|
-
playerCardsContainer.innerHTML = '';
|
|
425
|
-
|
|
426
|
-
// In heads-up, we show both hands at the end.
|
|
427
|
-
const showCards = isTerminal || (playerData.cards && !playerData.cards.includes(null));
|
|
428
|
-
|
|
429
|
-
(playerData.cards || [null, null]).forEach((cardStr) => {
|
|
430
|
-
playerCardsContainer.appendChild(createCardElement(cardStr, !showCards && cardStr !== null));
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// Update info area (right side)
|
|
435
|
-
const playerInfoArea = elements.playerInfoAreas[index];
|
|
436
|
-
if (playerInfoArea) {
|
|
437
|
-
playerInfoArea.querySelector('.player-stack-value').textContent = `${playerData.stack}`;
|
|
438
|
-
|
|
439
|
-
const betDisplay = playerInfoArea.querySelector('.bet-display');
|
|
440
|
-
if (playerData.currentBet > 0) {
|
|
441
|
-
if (data.lastMoves[index]) {
|
|
442
|
-
betDisplay.textContent = data.lastMoves[index];
|
|
443
|
-
} else {
|
|
444
|
-
if (playerData.isDealer) {
|
|
445
|
-
betDisplay.textContent = 'small blind';
|
|
446
|
-
} else {
|
|
447
|
-
betDisplay.textContent = 'big blind';
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
betDisplay.style.display = 'block';
|
|
451
|
-
} else {
|
|
452
|
-
betDisplay.style.display = 'none';
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
});
|
|
583
|
+
// Since the 4th and 5th street cards are appended to the communityCards array, we need to
|
|
584
|
+
// reverse it so that the added cards are put at the end of the display area on the board.
|
|
585
|
+
if (communityCards) communityCards.reverse();
|
|
456
586
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
elements.dealerButton.style.display = 'block';
|
|
461
|
-
// Remove previous dealer class
|
|
462
|
-
elements.dealerButton.classList.remove('dealer-player0', 'dealer-player1');
|
|
463
|
-
// Add new dealer class based on player index
|
|
464
|
-
elements.dealerButton.classList.add(`dealer-player${dealerPlayerIndex}`);
|
|
465
|
-
} else {
|
|
466
|
-
elements.dealerButton.style.display = 'none';
|
|
467
|
-
}
|
|
468
|
-
}
|
|
587
|
+
// Add actual cards
|
|
588
|
+
for (let i = 0; i < numCards; i++) {
|
|
589
|
+
elements.communityCardsContainer.appendChild(createCardElement(communityCards[i]));
|
|
469
590
|
}
|
|
470
591
|
|
|
471
|
-
//
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
592
|
+
// Fill remaining slots with empty cards
|
|
593
|
+
for (let i = numCards; i < numCommunityCards; i++) {
|
|
594
|
+
const emptyCard = document.createElement('div');
|
|
595
|
+
emptyCard.classList.add('card', 'card-empty');
|
|
596
|
+
elements.communityCardsContainer.appendChild(emptyCard);
|
|
476
597
|
}
|
|
477
598
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
if (!_ensurePokerTableElements(parent, options)) {
|
|
481
|
-
console.error('Renderer: Failed to ensure poker table elements.');
|
|
482
|
-
parent.innerHTML = '<p style="color:red;">Error: Could not create poker table structure.</p>';
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
599
|
+
elements.potDisplay.textContent = `Total Pot : ${pot}`;
|
|
485
600
|
|
|
486
|
-
|
|
487
|
-
|
|
601
|
+
players.forEach((playerData, index) => {
|
|
602
|
+
const playerNameElement = elements.playerNames[index];
|
|
603
|
+
if (playerNameElement) {
|
|
604
|
+
playerNameElement.textContent = playerData.name;
|
|
488
605
|
|
|
489
|
-
|
|
490
|
-
|
|
606
|
+
// Highlight current player's turn
|
|
607
|
+
if (playerData.isTurn && !isTerminal) {
|
|
608
|
+
playerNameElement.classList.add('current-turn');
|
|
609
|
+
} else {
|
|
610
|
+
playerNameElement.classList.remove('current-turn');
|
|
611
|
+
}
|
|
491
612
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
613
|
+
// Add winner class if player won
|
|
614
|
+
if (playerData.isWinner) {
|
|
615
|
+
playerNameElement.classList.add('winner');
|
|
616
|
+
} else {
|
|
617
|
+
playerNameElement.classList.remove('winner');
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Update thumbnail
|
|
622
|
+
const playerThumbnailElement = elements.playerThumbnails[index];
|
|
623
|
+
if (playerThumbnailElement && playerData.thumbnail) {
|
|
624
|
+
playerThumbnailElement.src = playerData.thumbnail;
|
|
625
|
+
playerThumbnailElement.style.display = 'block';
|
|
626
|
+
} else if (playerThumbnailElement) {
|
|
627
|
+
playerThumbnailElement.style.display = 'none';
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Update card area (left side)
|
|
631
|
+
const playerCardArea = elements.playerCardAreas[index];
|
|
632
|
+
if (playerCardArea) {
|
|
633
|
+
const playerCardsContainer = playerCardArea.querySelector('.player-cards-container');
|
|
634
|
+
playerCardsContainer.innerHTML = '';
|
|
635
|
+
|
|
636
|
+
// In heads-up, we show both hands at the end.
|
|
637
|
+
const showCards = isTerminal || (playerData.cards && !playerData.cards.includes(null));
|
|
638
|
+
|
|
639
|
+
(playerData.cards || [null, null]).forEach((cardStr) => {
|
|
640
|
+
playerCardsContainer.appendChild(createCardElement(cardStr, !showCards && cardStr !== null));
|
|
496
641
|
});
|
|
497
|
-
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// Update chip stacks on the table
|
|
645
|
+
if (elements.chipStacks[index]) {
|
|
646
|
+
updateChipStack(elements.chipStacks[index], playerData.currentBet);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// Update info area (right side)
|
|
650
|
+
const playerInfoArea = elements.playerInfoAreas[index];
|
|
651
|
+
if (playerInfoArea) {
|
|
652
|
+
// Highlight active player's pod
|
|
653
|
+
if (playerData.isTurn && !isTerminal) {
|
|
654
|
+
playerInfoArea.classList.add('active-player');
|
|
655
|
+
} else {
|
|
656
|
+
playerInfoArea.classList.remove('active-player');
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Highlight winner's pod
|
|
660
|
+
if (playerData.isWinner) {
|
|
661
|
+
playerInfoArea.classList.add('winner-player');
|
|
662
|
+
} else {
|
|
663
|
+
playerInfoArea.classList.remove('winner-player');
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
playerInfoArea.querySelector('.player-stack-value').textContent = `${playerData.stack}`;
|
|
667
|
+
|
|
668
|
+
const betDisplay = playerInfoArea.querySelector('.bet-display');
|
|
669
|
+
if (playerData.currentBet > 0) {
|
|
670
|
+
if (playerData.actionDisplayText) {
|
|
671
|
+
betDisplay.textContent = playerData.actionDisplayText;
|
|
672
|
+
} else {
|
|
673
|
+
betDisplay.textContent = '';
|
|
674
|
+
}
|
|
675
|
+
betDisplay.style.display = 'block';
|
|
676
|
+
} else {
|
|
677
|
+
betDisplay.style.display = 'none';
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
const dealerPlayerIndex = players.findIndex((p) => p.isDealer);
|
|
683
|
+
if (elements.dealerButton) {
|
|
684
|
+
if (dealerPlayerIndex !== -1) {
|
|
685
|
+
elements.dealerButton.style.display = 'block';
|
|
686
|
+
// Remove previous dealer class
|
|
687
|
+
elements.dealerButton.classList.remove('dealer-player0', 'dealer-player1');
|
|
688
|
+
// Add new dealer class based on player index
|
|
689
|
+
elements.dealerButton.classList.add(`dealer-player${dealerPlayerIndex}`);
|
|
690
|
+
} else {
|
|
691
|
+
elements.dealerButton.style.display = 'none';
|
|
692
|
+
}
|
|
498
693
|
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// --- MAIN EXECUTION LOGIC ---
|
|
697
|
+
const { parent } = options;
|
|
698
|
+
if (!parent) {
|
|
699
|
+
console.error('Renderer: Parent element not provided.');
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
_injectStyles(options);
|
|
704
|
+
|
|
705
|
+
if (!_ensurePokerTableElements(parent, options)) {
|
|
706
|
+
console.error('Renderer: Failed to ensure poker table elements.');
|
|
707
|
+
parent.innerHTML = '<p style="color:red;">Error: Could not create poker table structure.</p>';
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
const uiData = _parseKagglePokerState(options);
|
|
712
|
+
_renderPokerTableUI(uiData, options);
|
|
713
|
+
|
|
714
|
+
// Apply initial scale
|
|
715
|
+
_applyScale(parent);
|
|
716
|
+
|
|
717
|
+
// Watch for container size changes and reapply scale
|
|
718
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
719
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
720
|
+
_applyScale(parent);
|
|
721
|
+
});
|
|
722
|
+
resizeObserver.observe(parent);
|
|
723
|
+
}
|
|
499
724
|
}
|