kaggle-environments 1.21.0__py3-none-any.whl → 1.22.0__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/__init__.py +1 -1
- kaggle_environments/envs/open_spiel_env/games/repeated_poker/repeated_poker.js +673 -0
- kaggle_environments/envs/open_spiel_env/open_spiel_env.py +13 -0
- kaggle_environments/envs/open_spiel_env/test_open_spiel_env.py +19 -0
- {kaggle_environments-1.21.0.dist-info → kaggle_environments-1.22.0.dist-info}/METADATA +1 -1
- {kaggle_environments-1.21.0.dist-info → kaggle_environments-1.22.0.dist-info}/RECORD +9 -8
- {kaggle_environments-1.21.0.dist-info → kaggle_environments-1.22.0.dist-info}/WHEEL +0 -0
- {kaggle_environments-1.21.0.dist-info → kaggle_environments-1.22.0.dist-info}/entry_points.txt +0 -0
- {kaggle_environments-1.21.0.dist-info → kaggle_environments-1.22.0.dist-info}/licenses/LICENSE +0 -0
kaggle_environments/__init__.py
CHANGED
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
|
|
2
|
+
function renderer(options) {
|
|
3
|
+
// --- Elements and Style Injection ---
|
|
4
|
+
const elements = {
|
|
5
|
+
gameLayout: null,
|
|
6
|
+
pokerTableContainer: null,
|
|
7
|
+
pokerTable: null,
|
|
8
|
+
communityCardsContainer: null,
|
|
9
|
+
potDisplay: null,
|
|
10
|
+
playersContainer: null,
|
|
11
|
+
playerCardAreas: [],
|
|
12
|
+
playerInfoAreas: [],
|
|
13
|
+
dealerButton: null,
|
|
14
|
+
diagnosticHeader: null,
|
|
15
|
+
gameMessageArea: null,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const css = `
|
|
19
|
+
@font-face {
|
|
20
|
+
font-family: 'Zeitung Pro';
|
|
21
|
+
src:
|
|
22
|
+
url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/l?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
|
|
23
|
+
format("woff2"),
|
|
24
|
+
url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/d?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
|
|
25
|
+
format("woff"),
|
|
26
|
+
url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/a?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
|
|
27
|
+
format("opentype");
|
|
28
|
+
font-weight: normal;
|
|
29
|
+
font-style: normal;
|
|
30
|
+
}
|
|
31
|
+
@font-face {
|
|
32
|
+
font-family: 'Zeitung Pro';
|
|
33
|
+
src:
|
|
34
|
+
url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/l?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
|
|
35
|
+
format("woff2"),
|
|
36
|
+
url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/d?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
|
|
37
|
+
format("woff"),
|
|
38
|
+
url("https://use.typekit.net/af/37ff2c/00000000000000003b9b2a25/27/a?primer=7cdcb44be4a7db8877ffa5c0007b8dd865b3bbc383831fe2ea177f62257a9191&fvd=n7&v=3")
|
|
39
|
+
format("opentype");
|
|
40
|
+
font-weight: bold;
|
|
41
|
+
font-style: normal;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.poker-renderer-host {
|
|
45
|
+
width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;
|
|
46
|
+
font-family: 'Zeitung Pro', sans-serif; background-color: #2d3748; color: #fff;
|
|
47
|
+
overflow: hidden; padding: 1rem; box-sizing: border-box; position: relative;
|
|
48
|
+
}
|
|
49
|
+
.poker-game-layout { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; position: relative; max-width: 750px; max-height: 750px; }
|
|
50
|
+
.poker-table-container { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; max-width: 750px; max-height: 275px; }
|
|
51
|
+
.poker-table {
|
|
52
|
+
width: clamp(400px, 85vw, 750px); height: clamp(220px, 48vw, 275px);
|
|
53
|
+
background-color: #197631; border-radius: 24px; position: relative;
|
|
54
|
+
display: flex; align-items: center; justify-content: center;
|
|
55
|
+
margin: 0 60px;
|
|
56
|
+
}
|
|
57
|
+
.players-container {
|
|
58
|
+
position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 10;
|
|
59
|
+
}
|
|
60
|
+
.player-container {
|
|
61
|
+
position: absolute;
|
|
62
|
+
width: 100%;
|
|
63
|
+
pointer-events: none;
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-direction: column;
|
|
66
|
+
}
|
|
67
|
+
.player-container-0 { bottom: 0; flex-direction: column-reverse; }
|
|
68
|
+
.player-container-1 { top: 0; }
|
|
69
|
+
.player-area-wrapper {
|
|
70
|
+
display: flex;
|
|
71
|
+
justify-content: space-between;
|
|
72
|
+
align-items: center;
|
|
73
|
+
}
|
|
74
|
+
.player-card-area {
|
|
75
|
+
margin: 20px 60px; color: white; text-align: center;
|
|
76
|
+
display: flex; flex-direction: column; justify-content: center; align-items: center;
|
|
77
|
+
min-height: 100px; pointer-events: auto;
|
|
78
|
+
}
|
|
79
|
+
.player-info-area {
|
|
80
|
+
color: white;
|
|
81
|
+
min-width: 180px;
|
|
82
|
+
pointer-events: auto;
|
|
83
|
+
display: flex;
|
|
84
|
+
flex-direction: column;
|
|
85
|
+
justify-content: left;
|
|
86
|
+
align-items: left;
|
|
87
|
+
margin-right: 60px;
|
|
88
|
+
}
|
|
89
|
+
.player-container-0 .player-info-area { flex-direction: column-reverse; }
|
|
90
|
+
.player-name {
|
|
91
|
+
font-size: 32px; font-weight: 600;
|
|
92
|
+
white-space: nowrap;
|
|
93
|
+
overflow: hidden;
|
|
94
|
+
text-overflow: ellipsis;
|
|
95
|
+
color: white;
|
|
96
|
+
text-align: left;
|
|
97
|
+
padding: 10px 0;
|
|
98
|
+
margin: 0 60px;
|
|
99
|
+
}
|
|
100
|
+
.player-name.winner { color: #FFEB70; }
|
|
101
|
+
.player-stack { font-size: 32px; font-weight: 600; color: #ffffff; margin: 16px 0; display: flex; justify-content: space-between; align-items: center; }
|
|
102
|
+
.player-cards-container { min-height: 70px; display: flex; justify-content: flex-start; align-items:center; gap: 12px; }
|
|
103
|
+
.card {
|
|
104
|
+
display: flex; flex-direction: column; justify-content: space-between; align-items: center;
|
|
105
|
+
width: 80px; height: 112px; border: 2px solid #202124; border-radius: 8px;
|
|
106
|
+
background-color: white; color: black; font-weight: bold; text-align: center; overflow: hidden; position: relative;
|
|
107
|
+
padding: 6px;
|
|
108
|
+
}
|
|
109
|
+
.card-rank { font-family: 'Inter' sans-serif; font-size: 50px; line-height: 1; display: block; align-self: flex-start; }
|
|
110
|
+
.card-suit { width: 50px; height: 50px; display: block; margin-bottom: 2px; }
|
|
111
|
+
.card-suit svg { width: 100%; height: 100%; }
|
|
112
|
+
.card-red .card-rank { color: #B3261E; }
|
|
113
|
+
.card-red .card-suit svg { fill: #B3261E; }
|
|
114
|
+
.card-black .card-rank { color: #000000; }
|
|
115
|
+
.card-black .card-suit svg { fill: #000000; }
|
|
116
|
+
.card-blue .card-rank { color: #0B57D0; }
|
|
117
|
+
.card-blue .card-suit svg { fill: #0B57D0; }
|
|
118
|
+
.card-green .card-rank { color: #146C2E; }
|
|
119
|
+
.card-green .card-suit svg { fill: #146C2E; }
|
|
120
|
+
.card-back {
|
|
121
|
+
background-color: #2b6cb0;
|
|
122
|
+
background-image: linear-gradient(45deg, rgba(255,255,255,0.1) 25%, transparent 25%, transparent 75%, rgba(255,255,255,0.1) 75%, rgba(255,255,255,0.1)),
|
|
123
|
+
linear-gradient(-45deg, rgba(255,255,255,0.1) 25%, transparent 25%, transparent 75%, rgba(255,255,255,0.1) 75%, rgba(255,255,255,0.1));
|
|
124
|
+
background-size: 10px 10px; border: 2px solid #63b3ed;
|
|
125
|
+
}
|
|
126
|
+
.card-back .card-rank, .card-back .card-suit { display: none; }
|
|
127
|
+
.card-empty {
|
|
128
|
+
background-color: rgba(255, 255, 255, 0.1);
|
|
129
|
+
border: 2px solid rgba(32, 33, 36, 0.5);
|
|
130
|
+
background-image: none;
|
|
131
|
+
}
|
|
132
|
+
.card-empty .card-rank, .card-empty .card-suit { display: none; }
|
|
133
|
+
.community-cards-area { text-align: center; z-index: 10; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
|
|
134
|
+
.community-cards-container { min-height: 75px; display: flex; justify-content: center; align-items:center; margin-bottom: 0.5rem; gap: 12px; }
|
|
135
|
+
.pot-display { font-size: 40px; font-weight: bold; color: #ffffff; margin-bottom: 30px; }
|
|
136
|
+
.bet-display {
|
|
137
|
+
display: inline-block; padding: 10px 20px; border-radius: 12px;
|
|
138
|
+
background-color: #1a202c; color: #ffff;
|
|
139
|
+
font-family: 'Inter' sans-serif; font-size: 1.75rem; font-weigth: 600;
|
|
140
|
+
text-align: center;
|
|
141
|
+
height: 3rem; line-height: 3rem;
|
|
142
|
+
}
|
|
143
|
+
.blind-indicator { font-size: 0.7rem; color: #a0aec0; margin-top: 3px; }
|
|
144
|
+
.dealer-button {
|
|
145
|
+
width: 36px; height: 36px; background-color: #f0f0f0; color: #333; border-radius: 50%;
|
|
146
|
+
text-align: center; line-height: 36px; font-weight: bold; font-size: 1.5rem; position: absolute;
|
|
147
|
+
border: 3px solid #1EBEFF; box-shadow: 0 1px 3px rgba(0,0,0,0.3); z-index: 15; pointer-events: auto;
|
|
148
|
+
}
|
|
149
|
+
.dealer-button.dealer-player0 { bottom: 110px; }
|
|
150
|
+
.dealer-button.dealer-player1 { top: 110px; }
|
|
151
|
+
#game-message-area { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); background-color: rgba(0,0,0,0.6); padding: 5px 10px; border-radius: 5px; font-size: 0.9rem; z-index: 20;}
|
|
152
|
+
|
|
153
|
+
@media (max-width: 768px) {
|
|
154
|
+
.bet-display { font-size: 1.5rem; height: 2.2rem; line-height: 2.2rem; }
|
|
155
|
+
.card { width: 60px; height: 85px; } .card-rank { font-size: 35px; } .card-suit { width: 35px; height: 35px; }
|
|
156
|
+
.community-cards-container { gap: 6px; }
|
|
157
|
+
.player-card-area { min-height: 120px; }
|
|
158
|
+
.player-cards-container { gap: 6px; }
|
|
159
|
+
.player-info-area { min-width: 160px; }
|
|
160
|
+
.poker-game-layout { max-height: 700px; }
|
|
161
|
+
.pot-display { font-size: 35px; margin-bottom: 20px; }
|
|
162
|
+
}
|
|
163
|
+
@media (max-width: 600px) {
|
|
164
|
+
.bet-display { font-size: 20px; height: 40px; line-height: 40px; }
|
|
165
|
+
.card { width: 50px; height: 70px; padding: 2px; } .card-rank { font-size: 32px; } .card-suit { width: 32px; height: 32px; }
|
|
166
|
+
.community-cards-container { gap: 2px; }
|
|
167
|
+
.dealer-button { font-size: 20px; height: 24px; line-height: 24px; width: 24px; }
|
|
168
|
+
.dealer-button.dealer-player0 { bottom: 95px; }
|
|
169
|
+
.dealer-button.dealer-player1 { top: 95px; }
|
|
170
|
+
.player-card-area { min-height: 110px; margin: 0 0 0 40px;}
|
|
171
|
+
.player-cards-container { gap: 2px; }
|
|
172
|
+
.player-info-area { margin-right: 20px; }
|
|
173
|
+
.player-name { font-size: 30px; margin: 0 20px; }
|
|
174
|
+
.player-stack { font-size: 30px; }
|
|
175
|
+
.poker-game-layout { max-height: 600px; }
|
|
176
|
+
.poker-table { width: clamp(300px, 90vw, 600px); height: clamp(160px, 50vw, 200px); margin: 20px; }
|
|
177
|
+
.pot-display { font-size: 30px; margin-bottom: 20px; }
|
|
178
|
+
}
|
|
179
|
+
@media (max-width: 400px) {
|
|
180
|
+
.bet-display { font-size: 15px; height: 30px; line-height: 30px; }
|
|
181
|
+
.card { width: 40px; height: 56px; margin: 0 2px; padding: 2px; } .card-rank { font-size: 25px; } .card-suit { width: 25px; height: 25px; }
|
|
182
|
+
.community-cards-container { gap: 2px; }
|
|
183
|
+
.dealer-button { font-size: 15px; height: 20px; line-height: 20px; width: 20px; }
|
|
184
|
+
.dealer-button.dealer-player0 { bottom: 85px; }
|
|
185
|
+
.dealer-button.dealer-player1 { top: 85px; }
|
|
186
|
+
.player-card-area { margin: 0 0 0 30px;}
|
|
187
|
+
.player-cards-container { gap: 2px; }
|
|
188
|
+
.player-info-area { min-width: 100px; margin-right: 0; }
|
|
189
|
+
.player-name { font-size: 25px; }
|
|
190
|
+
.player-stack { font-size: 15px; }
|
|
191
|
+
.poker-game-layout { max-height: 500px; }
|
|
192
|
+
.poker-table { width: clamp(280px, 95vw, 380px); height: clamp(150px, 55vw, 150px); margin: 0;}
|
|
193
|
+
.pot-display { font-size: 25px; margin-bottom: 15px; }
|
|
194
|
+
}
|
|
195
|
+
`;
|
|
196
|
+
|
|
197
|
+
function _injectStyles(passedOptions) {
|
|
198
|
+
if (typeof document === 'undefined' || window.__poker_styles_injected) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const style = document.createElement('style');
|
|
202
|
+
style.textContent = css;
|
|
203
|
+
const parentForStyles = passedOptions && passedOptions.parent ? passedOptions.parent.ownerDocument.head : document.head;
|
|
204
|
+
if (parentForStyles && !parentForStyles.querySelector('style[data-poker-renderer-styles]')) {
|
|
205
|
+
style.setAttribute('data-poker-renderer-styles', 'true');
|
|
206
|
+
parentForStyles.appendChild(style);
|
|
207
|
+
}
|
|
208
|
+
window.__poker_styles_injected = true;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const suitSVGs = {
|
|
212
|
+
spades: '<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg"><path d="M31.9017 8.5459L31.9027 8.54688V8.54785L31.9642 8.62988C32.0049 8.68463 32.0647 8.76567 32.1419 8.86914C32.2968 9.07661 32.5214 9.37584 32.7982 9.74316C33.3519 10.4781 34.1164 11.4847 34.9583 12.5713C36.6487 14.7529 38.6314 17.23 39.8587 18.4951C40.5956 19.2546 42.6938 21.1061 45.0882 23.3057C47.4623 25.4866 50.1062 27.9917 51.8763 30.0146C53.659 32.052 54.5809 34.6512 54.9242 37.0439C55.2443 39.2762 55.07 41.3963 54.5648 42.7754L54.4593 43.041L54.4583 43.0439C54.2366 43.5604 53.4581 45.3752 51.889 47.0635C50.312 48.7602 47.9209 50.3437 44.5003 50.3438C41.1459 50.3437 38.4383 49.3111 36.5716 48.2812C35.668 47.7827 34.959 47.2827 34.4662 46.8984C34.6764 47.5682 35.0067 48.3733 35.5287 49.2432C35.8458 49.7716 36.3961 50.2525 37.0941 50.6953C37.7874 51.1352 38.5874 51.513 39.3636 51.8545C40.1218 52.1881 40.8886 52.4987 41.4437 52.7803C41.7223 52.9216 41.9834 53.0734 42.181 53.2383C42.3602 53.3878 42.5999 53.6413 42.5999 54C42.5999 54.3241 42.4172 54.5729 42.2318 54.7422C42.0426 54.9148 41.7911 55.0617 41.5101 55.1895C40.9443 55.4466 40.1512 55.6745 39.1976 55.8652C37.2827 56.2482 34.6237 56.5 31.5999 56.5C28.5752 56.5 25.9176 56.2484 23.9427 55.8662C22.957 55.6754 22.1264 55.4487 21.5003 55.1982C21.1878 55.0732 20.9125 54.9375 20.6908 54.7881C20.4761 54.6434 20.2705 54.4592 20.1527 54.2236L20.0999 54.1182V54C20.0999 53.6414 20.3397 53.3878 20.5189 53.2383C20.7165 53.0734 20.9776 52.9216 21.2562 52.7803C21.8113 52.4987 22.578 52.1881 23.3363 51.8545C24.1124 51.513 24.9125 51.1352 25.6058 50.6953C26.3038 50.2525 26.8541 49.7716 27.1712 49.2432C27.726 48.3186 28.0632 47.467 28.2708 46.7734C28.2466 46.7955 28.2233 46.8199 28.1976 46.8428C27.7563 47.2352 27.101 47.7542 26.2376 48.2725C24.5092 49.3098 21.9429 50.3437 18.5863 50.3438C15.1655 50.3437 12.7737 48.7603 11.1966 47.0635C9.6273 45.3749 8.84884 43.56 8.62728 43.0439L8.62631 43.041C8.04128 41.6783 7.81998 39.4248 8.16146 37.0439C8.50467 34.6513 9.42677 32.052 11.2093 30.0146C12.9793 27.9918 15.6234 25.4865 17.9977 23.3057C20.3921 21.1061 22.4903 19.2546 23.2272 18.4951C24.4545 17.23 26.4372 14.7529 28.1276 12.5713C28.9695 11.4847 29.734 10.4781 30.2877 9.74316C30.5645 9.37584 30.7891 9.07661 30.944 8.86914C31.0212 8.76567 31.081 8.68463 31.1217 8.62988L31.1832 8.54785V8.54688L31.1842 8.5459C31.4355 8.19531 31.8496 8 32.2859 8H32.7999C33.2363 8 33.6504 8.19531 33.9017 8.5459Z"/></svg>',
|
|
213
|
+
hearts: '<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg"><path d="M31.6667 56.9333L27.8 53.4667C23.3111 49.4222 19.6 45.9333 16.6667 43C13.7333 40.0667 11.4 37.4333 9.66667 35.1C7.93333 32.7667 6.72222 30.6222 6.03333 28.6667C5.34444 26.7111 5 24.7111 5 22.6667C5 18.4889 6.4 15 9.2 12.2C12 9.4 15.4889 8 19.6667 8C21.9778 8 24.1778 8.48889 26.2667 9.46667C28.3556 10.4444 30.1556 11.8222 31.6667 13.6C33.1778 11.8222 34.9778 10.4444 37.0667 9.46667C39.1556 8.48889 41.3556 8 43.6667 8C47.8444 8 51.3333 9.4 54.1333 12.2C56.9333 15 58.3333 18.4889 58.3333 22.6667C58.3333 24.7111 57.9889 26.7111 57.3 28.6667C56.6111 30.6222 55.4 32.7667 53.6667 35.1C51.9333 37.4333 49.6 40.0667 46.6667 43C43.7333 45.9333 40.0222 49.4222 35.5333 53.4667L31.6667 56.9333Z"/></svg>',
|
|
214
|
+
diamonds: '<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg"><path d="M32 58.3333L8 31.6667L32 5L56 31.6667L32 58.3333Z"/></svg>',
|
|
215
|
+
clubs: '<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg"><path d="M32.7422 8C39.0131 8.00014 44.0965 13.0836 44.0967 19.3545C44.0967 22.3905 42.9028 25.1463 40.9619 27.1836C42.108 26.7945 43.3357 26.5811 44.6133 26.5811C50.8842 26.5813 55.9678 31.6646 55.9678 37.9355C55.9677 44.2065 50.8842 49.2898 44.6133 49.29C40.7767 49.29 37.3866 47.3859 35.3311 44.4727C35.3545 44.6869 35.4 44.9939 35.4873 45.3721C35.6708 46.1669 36.0397 47.2784 36.7832 48.5176C37.1124 49.0661 37.683 49.5639 38.4043 50.0215C39.121 50.4762 39.9477 50.8671 40.749 51.2197C41.5324 51.5644 42.323 51.8854 42.8955 52.1758C43.1826 52.3214 43.4509 52.4767 43.6533 52.6455C43.8375 52.7992 44.0801 53.0572 44.0801 53.4199C44.0799 53.7476 43.8956 54.0007 43.7061 54.1738C43.5126 54.3503 43.2539 54.5014 42.9648 54.6328C42.3825 54.8974 41.5654 55.1324 40.582 55.3291C38.6066 55.7241 35.8618 55.9844 32.7412 55.9844C29.6198 55.9843 26.8772 55.7244 24.8398 55.3301C23.8233 55.1333 22.9671 54.9005 22.3223 54.6426C22.0002 54.5137 21.7169 54.3731 21.4893 54.2197C21.2688 54.0712 21.0593 53.8831 20.9395 53.6436L20.8867 53.5381V53.4199C20.8867 53.0575 21.1294 52.7992 21.3135 52.6455C21.5159 52.4766 21.7851 52.3214 22.0723 52.1758C22.6447 51.8855 23.4346 51.5643 24.2178 51.2197C25.019 50.8672 25.8458 50.4761 26.5625 50.0215C27.2837 49.5639 27.8543 49.066 28.1836 48.5176C28.9271 47.2784 29.297 46.1669 29.4805 45.3721C29.5675 44.9951 29.6113 44.6888 29.6348 44.4746C27.579 47.3866 24.1901 49.29 20.3545 49.29C14.0836 49.2899 9.00003 44.2065 9 37.9355C9 31.6646 14.0835 26.5812 20.3545 26.5811C21.9457 26.5811 23.4603 26.9091 24.835 27.5C22.7097 25.4365 21.3867 22.5506 21.3867 19.3545C21.3869 13.0835 26.4712 8 32.7422 8Z"/></svg>'
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// --- Card Parsing and Rendering ---
|
|
219
|
+
function acpcCardToDisplay(acpcCard) {
|
|
220
|
+
if (!acpcCard || acpcCard.length < 2) return { rank: '?', suit: '', original: acpcCard };
|
|
221
|
+
const rankChar = acpcCard[0].toUpperCase();
|
|
222
|
+
const suitChar = acpcCard[1].toLowerCase();
|
|
223
|
+
const rankMap = { 'T': '10', 'J': 'J', 'Q': 'Q', 'K': 'K', 'A': 'A' };
|
|
224
|
+
const suitMap = { 's': 'spades', 'h': 'hearts', 'd': 'diamonds', 'c': 'clubs' };
|
|
225
|
+
const rank = rankMap[rankChar] || rankChar;
|
|
226
|
+
const suit = suitMap[suitChar] || '';
|
|
227
|
+
return { rank, suit, original: acpcCard };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function createCardElement(cardStr, isHidden = false) {
|
|
231
|
+
const cardDiv = document.createElement('div');
|
|
232
|
+
cardDiv.classList.add('card');
|
|
233
|
+
if (isHidden || !cardStr || cardStr === '?' || cardStr === "??") {
|
|
234
|
+
cardDiv.classList.add('card-back');
|
|
235
|
+
} else {
|
|
236
|
+
const { rank, suit } = acpcCardToDisplay(cardStr);
|
|
237
|
+
const rankSpan = document.createElement('span');
|
|
238
|
+
rankSpan.classList.add('card-rank');
|
|
239
|
+
rankSpan.textContent = rank;
|
|
240
|
+
cardDiv.appendChild(rankSpan);
|
|
241
|
+
|
|
242
|
+
const suitSpan = document.createElement('span');
|
|
243
|
+
suitSpan.classList.add('card-suit');
|
|
244
|
+
|
|
245
|
+
if (suitSVGs[suit]) {
|
|
246
|
+
suitSpan.innerHTML = suitSVGs[suit];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
cardDiv.appendChild(suitSpan);
|
|
250
|
+
|
|
251
|
+
if (suit === 'hearts') cardDiv.classList.add('card-red');
|
|
252
|
+
else if (suit === 'spades') cardDiv.classList.add('card-black');
|
|
253
|
+
else if (suit === 'diamonds') cardDiv.classList.add('card-blue');
|
|
254
|
+
else if (suit === 'clubs') cardDiv.classList.add('card-green');
|
|
255
|
+
}
|
|
256
|
+
return cardDiv;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// --- Board Parsing and Rendering ---
|
|
260
|
+
function _ensurePokerTableElements(parentElement, passedOptions) {
|
|
261
|
+
if (!parentElement) return false;
|
|
262
|
+
parentElement.innerHTML = '';
|
|
263
|
+
parentElement.classList.add('poker-renderer-host');
|
|
264
|
+
|
|
265
|
+
elements.diagnosticHeader = document.createElement('h1');
|
|
266
|
+
elements.diagnosticHeader.id = 'poker-renderer-diagnostic-header';
|
|
267
|
+
elements.diagnosticHeader.textContent = "Poker Table Initialized (Live Data)";
|
|
268
|
+
elements.diagnosticHeader.style.cssText = "color: lime; background-color: black; padding: 5px; font-size: 12px; position: absolute; top: 0px; left: 0px; z-index: 10001; display: none;"; // Hidden by default
|
|
269
|
+
parentElement.appendChild(elements.diagnosticHeader);
|
|
270
|
+
|
|
271
|
+
elements.gameMessageArea = document.createElement('div');
|
|
272
|
+
elements.gameMessageArea.id = 'game-message-area';
|
|
273
|
+
parentElement.appendChild(elements.gameMessageArea);
|
|
274
|
+
|
|
275
|
+
elements.gameLayout = document.createElement('div');
|
|
276
|
+
elements.gameLayout.className = 'poker-game-layout';
|
|
277
|
+
parentElement.appendChild(elements.gameLayout);
|
|
278
|
+
|
|
279
|
+
elements.pokerTableContainer = document.createElement('div');
|
|
280
|
+
elements.pokerTableContainer.className = 'poker-table-container';
|
|
281
|
+
elements.gameLayout.appendChild(elements.pokerTableContainer);
|
|
282
|
+
|
|
283
|
+
elements.playersContainer = document.createElement('div');
|
|
284
|
+
elements.playersContainer.className = 'players-container';
|
|
285
|
+
elements.gameLayout.appendChild(elements.playersContainer);
|
|
286
|
+
|
|
287
|
+
elements.pokerTable = document.createElement('div');
|
|
288
|
+
elements.pokerTable.className = 'poker-table';
|
|
289
|
+
elements.pokerTableContainer.appendChild(elements.pokerTable);
|
|
290
|
+
|
|
291
|
+
const communityArea = document.createElement('div');
|
|
292
|
+
communityArea.className = 'community-cards-area';
|
|
293
|
+
elements.pokerTable.appendChild(communityArea);
|
|
294
|
+
|
|
295
|
+
elements.potDisplay = document.createElement('div');
|
|
296
|
+
elements.potDisplay.className = 'pot-display';
|
|
297
|
+
communityArea.appendChild(elements.potDisplay);
|
|
298
|
+
|
|
299
|
+
elements.communityCardsContainer = document.createElement('div');
|
|
300
|
+
elements.communityCardsContainer.className = 'community-cards-container';
|
|
301
|
+
communityArea.appendChild(elements.communityCardsContainer);
|
|
302
|
+
|
|
303
|
+
elements.playerContainers = [];
|
|
304
|
+
elements.playerCardAreas = [];
|
|
305
|
+
elements.playerInfoAreas = [];
|
|
306
|
+
elements.playerNames = [];
|
|
307
|
+
|
|
308
|
+
for (let i = 0; i < 2; i++) {
|
|
309
|
+
// Create player container that groups all player elements
|
|
310
|
+
const playerContainer = document.createElement('div');
|
|
311
|
+
playerContainer.className = `player-container player-container-${i}`;
|
|
312
|
+
elements.playersContainer.appendChild(playerContainer);
|
|
313
|
+
elements.playerContainers.push(playerContainer);
|
|
314
|
+
|
|
315
|
+
// Player name
|
|
316
|
+
const playerName = document.createElement('div');
|
|
317
|
+
playerName.className = `player-name`;
|
|
318
|
+
playerName.textContent = `Player ${i}`;
|
|
319
|
+
playerContainer.appendChild(playerName);
|
|
320
|
+
elements.playerNames.push(playerName);
|
|
321
|
+
|
|
322
|
+
// Create wrapper for card and info areas
|
|
323
|
+
const playerAreaWrapper = document.createElement('div');
|
|
324
|
+
playerAreaWrapper.className = 'player-area-wrapper';
|
|
325
|
+
playerContainer.appendChild(playerAreaWrapper);
|
|
326
|
+
|
|
327
|
+
// Card area (left side)
|
|
328
|
+
const playerCardArea = document.createElement('div');
|
|
329
|
+
playerCardArea.className = `player-card-area`;
|
|
330
|
+
playerCardArea.innerHTML = `
|
|
331
|
+
<div class="player-cards-container"></div>
|
|
332
|
+
`;
|
|
333
|
+
playerAreaWrapper.appendChild(playerCardArea);
|
|
334
|
+
elements.playerCardAreas.push(playerCardArea);
|
|
335
|
+
|
|
336
|
+
// TODO: Render chip stack
|
|
337
|
+
// Info area (right side)
|
|
338
|
+
const playerInfoArea = document.createElement('div');
|
|
339
|
+
playerInfoArea.className = `player-info-area`;
|
|
340
|
+
playerInfoArea.innerHTML = `
|
|
341
|
+
<div class="player-stack">
|
|
342
|
+
<span class="player-stack-value">0</span>
|
|
343
|
+
</div>
|
|
344
|
+
<div class="bet-display" style="display:none;">Bet : 0</div>
|
|
345
|
+
`;
|
|
346
|
+
playerAreaWrapper.appendChild(playerInfoArea);
|
|
347
|
+
elements.playerInfoAreas.push(playerInfoArea);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
elements.dealerButton = document.createElement('div');
|
|
351
|
+
elements.dealerButton.className = 'dealer-button';
|
|
352
|
+
elements.dealerButton.textContent = 'D';
|
|
353
|
+
elements.dealerButton.style.display = 'none';
|
|
354
|
+
elements.playersContainer.appendChild(elements.dealerButton);
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function _parseACPCState(acpcState) {
|
|
359
|
+
const result = {
|
|
360
|
+
p0cards: '',
|
|
361
|
+
p1cards: '',
|
|
362
|
+
communityCards: '',
|
|
363
|
+
p0bet: 0,
|
|
364
|
+
p1bet: 0,
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
// Split the string into its main lines
|
|
368
|
+
const lines = acpcState.trim().split('\n');
|
|
369
|
+
if (lines.length < 2) {
|
|
370
|
+
console.error("Invalid state string format.");
|
|
371
|
+
return result;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const stateLine = lines[0]; // example: "STATE:0:r5c/cr11c/:6cKd|AsJc/7hQh6d/2c"
|
|
375
|
+
const spentLine = lines[1]; // example: "Spent: [P0: 11 P1: 11 ]"
|
|
376
|
+
|
|
377
|
+
// --- 1. Parse the State Line ---
|
|
378
|
+
if (stateLine) {
|
|
379
|
+
const stateParts = stateLine.split(':');
|
|
380
|
+
|
|
381
|
+
// The card string is always the last part
|
|
382
|
+
const cardString = stateParts[stateParts.length - 1]; // example: "6cKd|AsJc/7hQh6d/2c"
|
|
383
|
+
|
|
384
|
+
// Split card string by '/' to separate hand block from board blocks
|
|
385
|
+
const cardSegments = cardString.split('/'); // example: ["6cKd|AsJc", "7hQh6d", "2c"]
|
|
386
|
+
|
|
387
|
+
// Parse the first segment (player hands)
|
|
388
|
+
if (cardSegments[0]) {
|
|
389
|
+
const playerHands = cardSegments[0].split('|');
|
|
390
|
+
if (playerHands.length >= 2) {
|
|
391
|
+
// example: "6cKd"
|
|
392
|
+
result.p0cards = playerHands[0];
|
|
393
|
+
result.p1cards = playerHands[1];
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// The rest of the segments are community cards, one per street
|
|
398
|
+
result.communityCards = cardSegments
|
|
399
|
+
.slice(1) // gets all elements AFTER the player hands
|
|
400
|
+
.filter(Boolean) // removes any empty strings (e.g., from a trailing "/")
|
|
401
|
+
.join(''); // joins the remaining segments into a single string
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// --- 2. Parse the Spent Line ---
|
|
405
|
+
if (spentLine) {
|
|
406
|
+
const p0BetMatch = spentLine.match(/P0:\s*(\d+)/);
|
|
407
|
+
const p1BetMatch = spentLine.match(/P1:\s*(\d+)/);
|
|
408
|
+
|
|
409
|
+
if (p0BetMatch) {
|
|
410
|
+
result.p0bet = parseInt(p0BetMatch[1], 10);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (p1BetMatch) {
|
|
414
|
+
result.p1bet = parseInt(p1BetMatch[1], 10);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return result;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function _getCurrentStepUniversalPokerJSON(options) {
|
|
422
|
+
const { environment, step } = options;
|
|
423
|
+
|
|
424
|
+
const agentSteps = environment.info.stateHistory.filter(s => JSON.parse(JSON.parse(s).current_universal_poker_json).current_player !== -1);
|
|
425
|
+
|
|
426
|
+
const currentStep = agentSteps[step];
|
|
427
|
+
return JSON.parse(JSON.parse(currentStep).current_universal_poker_json);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// --- State Parsing ---
|
|
431
|
+
function _parseKagglePokerState(options) {
|
|
432
|
+
const { environment, step } = options;
|
|
433
|
+
const numPlayers = 2;
|
|
434
|
+
|
|
435
|
+
// --- Default State ---
|
|
436
|
+
const defaultUIData = {
|
|
437
|
+
players: Array(numPlayers).fill(null).map((_, i) => {
|
|
438
|
+
const agentName = environment?.info?.TeamNames?.[i] ||
|
|
439
|
+
`Player ${i}`;
|
|
440
|
+
return {
|
|
441
|
+
id: `player${i}`,
|
|
442
|
+
name: agentName,
|
|
443
|
+
stack: 0,
|
|
444
|
+
cards: [], // Will be filled with nulls or cards
|
|
445
|
+
currentBet: 0,
|
|
446
|
+
position: i === 0 ? "Small Blind" : "Big Blind",
|
|
447
|
+
isDealer: i === 0,
|
|
448
|
+
isTurn: false,
|
|
449
|
+
status: "Waiting...",
|
|
450
|
+
reward: null
|
|
451
|
+
};
|
|
452
|
+
}),
|
|
453
|
+
communityCards: [],
|
|
454
|
+
pot: 0,
|
|
455
|
+
isTerminal: false,
|
|
456
|
+
gameMessage: "Initializing...",
|
|
457
|
+
rawObservation: null, // For debugging
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// --- Step Validation ---
|
|
461
|
+
if (!environment || !environment.steps || !environment.steps[step] || !environment.info) {
|
|
462
|
+
return defaultUIData;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
currentStateHistory = JSON.parse(environment.info.stateHistory[step]);
|
|
466
|
+
currentUniversalPokerState = JSON.parse(currentStateHistory.current_universal_poker_json);
|
|
467
|
+
|
|
468
|
+
// TODO: Handle the flop phase steps (chance steps)
|
|
469
|
+
|
|
470
|
+
currentUniversalPokerJSON = _getCurrentStepUniversalPokerJSON(options);
|
|
471
|
+
currentStepFromStateHistory = _parseACPCState(currentUniversalPokerJSON.acpc_state);
|
|
472
|
+
|
|
473
|
+
const currentStepAgents = environment.steps[step];
|
|
474
|
+
if (!currentStepAgents || currentStepAgents.length < numPlayers) {
|
|
475
|
+
defaultUIData.gameMessage = "Waiting for agent data...";
|
|
476
|
+
return defaultUIData;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
const pot_size = currentStepFromStateHistory.p0bet + currentStepFromStateHistory.p1bet;
|
|
481
|
+
const player_contributions = [currentStepFromStateHistory.p0bet, currentStepFromStateHistory.p1bet];
|
|
482
|
+
const starting_stacks = currentUniversalPokerJSON.starting_stacks;
|
|
483
|
+
const player_hands = [
|
|
484
|
+
currentStepFromStateHistory.p0cards ? currentStepFromStateHistory.p0cards.match(/.{1,2}/g) : [],
|
|
485
|
+
currentStepFromStateHistory.p1cards ? currentStepFromStateHistory.p1cards.match(/.{1,2}/g) : [],
|
|
486
|
+
];
|
|
487
|
+
const board_cards = currentStepFromStateHistory.communityCards ? currentStepFromStateHistory.communityCards.match(/.{1,2}/g).reverse() : [];
|
|
488
|
+
const current_player = currentStepFromStateHistory.current_player;
|
|
489
|
+
const betting_history = currentStepFromStateHistory.betting_history;
|
|
490
|
+
|
|
491
|
+
// TODO: Add odds, best_five_card_hands best_hand_rank_types
|
|
492
|
+
|
|
493
|
+
const isTerminal = false // TODO: read isTerminal from observation
|
|
494
|
+
defaultUIData.isTerminal = isTerminal;
|
|
495
|
+
defaultUIData.pot = pot_size || 0;
|
|
496
|
+
defaultUIData.communityCards = board_cards || [];
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
// --- Update Player Pods ---
|
|
500
|
+
for (let i = 0; i < numPlayers; i++) {
|
|
501
|
+
const pData = defaultUIData.players[i];
|
|
502
|
+
const contribution = player_contributions ? player_contributions[i] : 0;
|
|
503
|
+
const startStack = starting_stacks ? starting_stacks[i] : 0;
|
|
504
|
+
|
|
505
|
+
pData.currentBet = contribution;
|
|
506
|
+
pData.stack = startStack - contribution;
|
|
507
|
+
pData.cards = (player_hands[i] || []).map(c => c === "??" ? null : c);
|
|
508
|
+
pData.isTurn = String(i) === String(current_player);
|
|
509
|
+
pData.status = pData.position; // Default status
|
|
510
|
+
|
|
511
|
+
if (isTerminal) {
|
|
512
|
+
const reward = environment.rewards ? environment.rewards[i] : null;
|
|
513
|
+
pData.reward = reward;
|
|
514
|
+
if (reward > 0) {
|
|
515
|
+
pData.name = `${pData.name} wins 🎉`;
|
|
516
|
+
pData.isWinner = true;
|
|
517
|
+
pData.status = null;
|
|
518
|
+
} else {
|
|
519
|
+
pData.status = null;
|
|
520
|
+
}
|
|
521
|
+
} else if (pData.stack === 0 && pData.currentBet > 0) {
|
|
522
|
+
pData.status = "All-in";
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Handle folded player status
|
|
527
|
+
if (!isTerminal && betting_history && betting_history.includes('f')) {
|
|
528
|
+
// A simple fold check: the player who didn't make the last action and isn't the current player might have folded.
|
|
529
|
+
// This is a simplification. A more robust parser would track the betting sequence.
|
|
530
|
+
const lastAction = betting_history.slice(-1);
|
|
531
|
+
if (lastAction === 'f') {
|
|
532
|
+
// Find who is NOT the current player
|
|
533
|
+
const nonCurrentPlayerIndex = current_player === '0' ? 1 : 0;
|
|
534
|
+
// If they are not all-in, they folded.
|
|
535
|
+
if (defaultUIData.players[nonCurrentPlayerIndex].status !== 'All-in') {
|
|
536
|
+
defaultUIData.players[nonCurrentPlayerIndex].status = "Folded";
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
// --- Set Game Message ---
|
|
543
|
+
if (isTerminal) {
|
|
544
|
+
const winnerIndex = environment.rewards ? environment.rewards.findIndex(r => r > 0) : -1;
|
|
545
|
+
if (winnerIndex !== -1) {
|
|
546
|
+
defaultUIData.gameMessage = `Player ${winnerIndex} wins!`;
|
|
547
|
+
} else {
|
|
548
|
+
defaultUIData.gameMessage = "Game Over.";
|
|
549
|
+
}
|
|
550
|
+
} else if (current_player === "chance") {
|
|
551
|
+
defaultUIData.gameMessage = `Dealing...`;
|
|
552
|
+
} else {
|
|
553
|
+
defaultUIData.gameMessage = `Player ${current_player}'s turn.`;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
return defaultUIData;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
function _renderPokerTableUI(data, passedOptions) {
|
|
561
|
+
if (!elements.pokerTable || !data) return;
|
|
562
|
+
const { players, communityCards, pot, isTerminal, gameMessage } = data;
|
|
563
|
+
|
|
564
|
+
if (elements.diagnosticHeader && data.rawObservation) {
|
|
565
|
+
// Optional: Show diagnostics for debugging
|
|
566
|
+
// elements.diagnosticHeader.textContent = `[${passedOptions.step}] P_TURN:${data.rawObservation.current_player} POT:${data.pot}`;
|
|
567
|
+
// elements.diagnosticHeader.style.display = 'block';
|
|
568
|
+
}
|
|
569
|
+
if (elements.gameMessageArea) {
|
|
570
|
+
elements.gameMessageArea.textContent = gameMessage;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
elements.communityCardsContainer.innerHTML = '';
|
|
574
|
+
// Always show 5 slots for the river
|
|
575
|
+
// Display cards left to right, with empty slots at the end
|
|
576
|
+
const numCommunityCards = 5;
|
|
577
|
+
const numCards = communityCards ? communityCards.length : 0;
|
|
578
|
+
|
|
579
|
+
// Since the 4th and 5th street cards are appended to the communityCards array, we need to
|
|
580
|
+
// reverse it so that the added cards are put at the end of the display area on the board.
|
|
581
|
+
if (communityCards) communityCards.reverse();
|
|
582
|
+
|
|
583
|
+
// Add actual cards
|
|
584
|
+
for (let i = 0; i < numCards; i++) {
|
|
585
|
+
elements.communityCardsContainer.appendChild(createCardElement(communityCards[i]));
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// Fill remaining slots with empty cards
|
|
589
|
+
for (let i = numCards; i < numCommunityCards; i++) {
|
|
590
|
+
const emptyCard = document.createElement('div');
|
|
591
|
+
emptyCard.classList.add('card', 'card-empty');
|
|
592
|
+
elements.communityCardsContainer.appendChild(emptyCard);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
elements.potDisplay.textContent = `Pot : ${pot}`;
|
|
596
|
+
|
|
597
|
+
players.forEach((playerData, index) => {
|
|
598
|
+
const playerNameElement = elements.playerNames[index];
|
|
599
|
+
if (playerNameElement) {
|
|
600
|
+
const playerNameText = playerData.isTurn && !isTerminal ? `${playerData.name} responding...` : playerData.name;
|
|
601
|
+
playerNameElement.textContent = playerNameText;
|
|
602
|
+
|
|
603
|
+
// Add winner class if player won
|
|
604
|
+
if (playerData.isWinner) {
|
|
605
|
+
playerNameElement.classList.add('winner');
|
|
606
|
+
} else {
|
|
607
|
+
playerNameElement.classList.remove('winner');
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Update card area (left side)
|
|
612
|
+
const playerCardArea = elements.playerCardAreas[index];
|
|
613
|
+
if (playerCardArea) {
|
|
614
|
+
|
|
615
|
+
const playerCardsContainer = playerCardArea.querySelector('.player-cards-container');
|
|
616
|
+
playerCardsContainer.innerHTML = '';
|
|
617
|
+
|
|
618
|
+
// In heads-up, we show both hands at the end.
|
|
619
|
+
const showCards = isTerminal || (playerData.cards && !playerData.cards.includes(null));
|
|
620
|
+
|
|
621
|
+
(playerData.cards || [null, null]).forEach(cardStr => {
|
|
622
|
+
playerCardsContainer.appendChild(createCardElement(cardStr, !showCards && cardStr !== null));
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Update info area (right side)
|
|
627
|
+
const playerInfoArea = elements.playerInfoAreas[index];
|
|
628
|
+
if (playerInfoArea) {
|
|
629
|
+
playerInfoArea.querySelector('.player-stack-value').textContent = `${playerData.stack}`;
|
|
630
|
+
|
|
631
|
+
const betDisplay = playerInfoArea.querySelector('.bet-display');
|
|
632
|
+
if (playerData.currentBet > 0) {
|
|
633
|
+
betDisplay.textContent = `Bet: ${playerData.currentBet}`;
|
|
634
|
+
betDisplay.style.display = 'block';
|
|
635
|
+
} else {
|
|
636
|
+
betDisplay.style.display = 'none';
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
const dealerPlayerIndex = players.findIndex(p => p.isDealer);
|
|
642
|
+
if (elements.dealerButton) {
|
|
643
|
+
if (dealerPlayerIndex !== -1) {
|
|
644
|
+
elements.dealerButton.style.display = 'block';
|
|
645
|
+
// Remove previous dealer class
|
|
646
|
+
elements.dealerButton.classList.remove('dealer-player0', 'dealer-player1');
|
|
647
|
+
// Add new dealer class based on player index
|
|
648
|
+
elements.dealerButton.classList.add(`dealer-player${dealerPlayerIndex}`);
|
|
649
|
+
} else {
|
|
650
|
+
elements.dealerButton.style.display = 'none';
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
// --- MAIN EXECUTION LOGIC ---
|
|
657
|
+
const { parent } = options;
|
|
658
|
+
if (!parent) {
|
|
659
|
+
console.error("Renderer: Parent element not provided.");
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
_injectStyles(options);
|
|
664
|
+
|
|
665
|
+
if (!_ensurePokerTableElements(parent, options)) {
|
|
666
|
+
console.error("Renderer: Failed to ensure poker table elements.");
|
|
667
|
+
parent.innerHTML = '<p style="color:red;">Error: Could not create poker table structure.</p>';
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const uiData = _parseKagglePokerState(options);
|
|
672
|
+
_renderPokerTableUI(uiData, options);
|
|
673
|
+
}
|
|
@@ -7,6 +7,7 @@ import logging
|
|
|
7
7
|
import os
|
|
8
8
|
import pathlib
|
|
9
9
|
import random
|
|
10
|
+
import re
|
|
10
11
|
import sys
|
|
11
12
|
from typing import Any, Callable
|
|
12
13
|
|
|
@@ -222,6 +223,18 @@ def interpreter(
|
|
|
222
223
|
# --- Get and maybe initialize game and state on the env object ---
|
|
223
224
|
if not hasattr(env, "os_game"):
|
|
224
225
|
game_string = env.configuration.get("openSpielGameString")
|
|
226
|
+
# TODO(jhtschultz): Consolidate these competition-specific config fields
|
|
227
|
+
if env.configuration.get("setNumHands", None):
|
|
228
|
+
if "repeated_poker" not in game_string:
|
|
229
|
+
raise ValueError(
|
|
230
|
+
"setNumHands only supported for repeated_poker,"
|
|
231
|
+
f" not {game_string}"
|
|
232
|
+
)
|
|
233
|
+
game_string = re.sub(
|
|
234
|
+
r'(max_num_hands=)\d+',
|
|
235
|
+
f'max_num_hands={env.configuration.get("setNumHands")}',
|
|
236
|
+
game_string,
|
|
237
|
+
)
|
|
225
238
|
env.os_game = pyspiel.load_game(game_string)
|
|
226
239
|
if not hasattr(env, "os_state"):
|
|
227
240
|
env.os_state = env.os_game.new_initial_state()
|
|
@@ -250,6 +250,25 @@ class OpenSpielEnvTest(absltest.TestCase):
|
|
|
250
250
|
self.assertTrue(env.done)
|
|
251
251
|
self.assertEqual(env.toJSON()["rewards"], [0.0, 0.0])
|
|
252
252
|
|
|
253
|
+
def test_poker_set_num_hands(self):
|
|
254
|
+
num_hands = 2
|
|
255
|
+
config = {
|
|
256
|
+
"setNumHands": num_hands,
|
|
257
|
+
}
|
|
258
|
+
env = make(
|
|
259
|
+
'open_spiel_repeated_poker',
|
|
260
|
+
config,
|
|
261
|
+
debug=True,
|
|
262
|
+
)
|
|
263
|
+
env.reset()
|
|
264
|
+
env.step([{"submission": -1}, {"submission": -1}]) # Initial setup step.
|
|
265
|
+
for i in range(num_hands):
|
|
266
|
+
if i % 2 == 0:
|
|
267
|
+
env.step([{"submission": -1}, {"submission": 0}])
|
|
268
|
+
else:
|
|
269
|
+
env.step([{"submission": 0}, {"submission": -1}])
|
|
270
|
+
self.assertTrue(env.done)
|
|
271
|
+
self.assertEqual(env.toJSON()["rewards"], [0.0, 0.0])
|
|
253
272
|
|
|
254
273
|
if __name__ == "__main__":
|
|
255
274
|
absltest.main()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
kaggle_environments/__init__.py,sha256=
|
|
1
|
+
kaggle_environments/__init__.py,sha256=AYfIeyZyz2aLnvMn3LB0bkpRHI8GlkxVYFnbjBiyvSs,2556
|
|
2
2
|
kaggle_environments/agent.py,sha256=cKEEUn61thBKGSTXhG6jnJnv9c9ACJvKYUkLFifoe0Q,7367
|
|
3
3
|
kaggle_environments/api.py,sha256=On1ubCgTdwkAQCAb3da138VuQ6ZyesXEVty9Of5A5hU,745
|
|
4
4
|
kaggle_environments/core.py,sha256=3pcj-S6L6BnSxGF_fjLnqW7AWrI6Lp9CDcOKj3W6BgI,27613
|
|
@@ -167,9 +167,9 @@ kaggle_environments/envs/mab/mab.py,sha256=q1ZTAjK2f_zG3fnGBmy_PYY4Ce6LHcv7ELgLD
|
|
|
167
167
|
kaggle_environments/envs/open_spiel_env/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
168
168
|
kaggle_environments/envs/open_spiel_env/html_playthrough_generator.py,sha256=KFAL57uTpSmkK9up2mfcO3aL17SjzKmHLWz0x00OD5M,941
|
|
169
169
|
kaggle_environments/envs/open_spiel_env/observation.py,sha256=7eLE_2qiApuh7rIL7FiS7gHRBryy_EAy1IuDAf3yCHE,5006
|
|
170
|
-
kaggle_environments/envs/open_spiel_env/open_spiel_env.py,sha256=
|
|
170
|
+
kaggle_environments/envs/open_spiel_env/open_spiel_env.py,sha256=bMpf3Szq2DY23Us_ZH5BDrSNKwWCbJEieWf4V94oVSE,22972
|
|
171
171
|
kaggle_environments/envs/open_spiel_env/proxy.py,sha256=4715tbRred58LB-Ht6S3s6xelRc8ZRnADBwcxUnJDUY,5134
|
|
172
|
-
kaggle_environments/envs/open_spiel_env/test_open_spiel_env.py,sha256=
|
|
172
|
+
kaggle_environments/envs/open_spiel_env/test_open_spiel_env.py,sha256=kd3fMmH1b9Yt98_BZyI4YAj5j8fdz04x-vM9PnzyFq8,10352
|
|
173
173
|
kaggle_environments/envs/open_spiel_env/games/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
174
174
|
kaggle_environments/envs/open_spiel_env/games/chess/chess.js,sha256=tHf178LHG3cXdXEoY9KS2yq8S8Ss9X1vQZMPT48zgCs,45639
|
|
175
175
|
kaggle_environments/envs/open_spiel_env/games/chess/image_config.jsonl,sha256=S2WMUA6VfDVPFaVAZ-DKyeh-2CTbLxoM4xRoDuaP7Yo,830
|
|
@@ -180,6 +180,7 @@ kaggle_environments/envs/open_spiel_env/games/connect_four/connect_four_proxy.py
|
|
|
180
180
|
kaggle_environments/envs/open_spiel_env/games/go/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
181
181
|
kaggle_environments/envs/open_spiel_env/games/go/go.js,sha256=SWUPrnQCMBlDjUiKTgVn9LeTUM85YbR10JRrq3ddw14,23751
|
|
182
182
|
kaggle_environments/envs/open_spiel_env/games/go/go_proxy.py,sha256=_b-PTFlN7FUtjSx26ciR6Os4rTop8A6vemF86HMYMO8,3407
|
|
183
|
+
kaggle_environments/envs/open_spiel_env/games/repeated_poker/repeated_poker.js,sha256=kkUvf-e4cU9qZL0ijAXmWBSUIUzZclL_6IcH7yG262A,33182
|
|
183
184
|
kaggle_environments/envs/open_spiel_env/games/tic_tac_toe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
184
185
|
kaggle_environments/envs/open_spiel_env/games/tic_tac_toe/tic_tac_toe.js,sha256=OD7FbhhOqmL8OC7UqPt0S9znwcUY4YTuhRCdsBd3ALE,17339
|
|
185
186
|
kaggle_environments/envs/open_spiel_env/games/tic_tac_toe/tic_tac_toe_proxy.py,sha256=r1A2Yl0vapJRrTEnvwfP9-P-uz_xtyWdWKXGsRXdR4o,2937
|
|
@@ -223,8 +224,8 @@ kaggle_environments/envs/werewolf/game/protocols/chat.py,sha256=wFewQogic1CHr4AW
|
|
|
223
224
|
kaggle_environments/envs/werewolf/game/protocols/factory.py,sha256=hg9Xj5Z-8USmqhouVzo8b7Ktl91xzFsE5_8naD6yErY,2316
|
|
224
225
|
kaggle_environments/envs/werewolf/game/protocols/vote.py,sha256=hKw64ubLMCIAIG5IcmNeV9MPTWWmWpkkCAyia_5kXn0,20716
|
|
225
226
|
kaggle_environments/static/player.html,sha256=Icl5yYscPe4BRoWt0HLOSRJWnznQq2MdTHHCaC2OrQQ,27753
|
|
226
|
-
kaggle_environments-1.
|
|
227
|
-
kaggle_environments-1.
|
|
228
|
-
kaggle_environments-1.
|
|
229
|
-
kaggle_environments-1.
|
|
230
|
-
kaggle_environments-1.
|
|
227
|
+
kaggle_environments-1.22.0.dist-info/entry_points.txt,sha256=h03sq76TdcHvXKcsre1Qm3lIni9dkWehu61xJqI-p8k,69
|
|
228
|
+
kaggle_environments-1.22.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
229
|
+
kaggle_environments-1.22.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
230
|
+
kaggle_environments-1.22.0.dist-info/METADATA,sha256=k__Yjug4lVv4o1ueT4flW13EMF-GBOcsb4aP2o9ocaw,916
|
|
231
|
+
kaggle_environments-1.22.0.dist-info/RECORD,,
|
|
File without changes
|
{kaggle_environments-1.21.0.dist-info → kaggle_environments-1.22.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{kaggle_environments-1.21.0.dist-info → kaggle_environments-1.22.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|