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