PageSourceSearch

https://perfectplay.dev/wong-halves

html perfectplay.dev collected 2026-10-02 01:52:28 UTC 16,288 bytes, 576 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="UTF-8">
5  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6  <title>Wong Halves Blackjack Calculator | PerfectPlay</title>
7  <meta name="description" content="Wong Halves blackjack calculator. Fractional level-three card counting assistant with live stats and betting ramp.">
8  <link rel="canonical" href="https://perfectplay.dev/wong-halves">
9
10  <!-- JSON-LD Structured Schema -->
11  
11<script type="application/ld+json">
12  {
13    "@context": "https://schema.org",
14    "@type": "SoftwareApplication",
15    "name": "Wong Halves Blackjack Calculator",
16    "url": "https://perfectplay.dev/wong-halves",
17    "description": "Wong Halves blackjack calculator. Fractional level-three card counting assistant with live stats and betting ramp.",
18    "applicationCategory": "GameApplication",
19    "operatingSystem": "All"
20  }
21  </script>
21
22
23  <link rel="preconnect" href="https://fonts.googleapis.com">
24  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
25  <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;600;700;800&family=Source+Code+Pro:wght@300;400;500;600;700&display=swap" rel="stylesheet">
26  <link rel="stylesheet" href="style.css">
27  <style>
28    :root {
29      --bg1: #7a0000;
30      --bg2: #b00000;
31      --card: rgba(255,255,255,0.12);
32      --card-border: rgba(255,255,255,0.18);
33      --text: #fff7f7;
34      --muted: rgba(255,247,247,0.78);
35      --accent: #ffd9d9;
36      --shadow: 0 10px 30px rgba(0,0,0,0.22);
37    }
38    
39    body {
40      margin: 0;
41      padding: 0;
42      background: #000;
43      font-family: Arial, sans-serif;
44      color: var(--text);
45      background: linear-gradient(135deg, var(--bg1), var(--bg2));
46      min-height: 100vh;
47      box-sizing: border-box;
48      padding-top: 90px;
49    }
50
51    .wh-wrap {
52      max-width: 1100px;
53      margin: 0 auto;
54      padding: 18px;
55    }
56
57    .wh-header {
58      display: flex;
59      justify-content: space-between;
60      align-items: flex-start;
61      gap: 12px;
62      margin-bottom: 16px;
63    }
64
65    .wh-title {
66      font-size: 28px;
67      font-weight: 700;
68      line-height: 1.1;
69      margin: 0;
70    }
71
72    .wh-sub {
73      font-size: 14px;
74      color: var(--muted);
75      margin-top: 6px;
76    }
77
78    .wh-row {
79      display: grid;
80      grid-template-columns: repeat(2, minmax(0,1fr));
81      gap: 10px;
82    }
83
84    .wh-field {
85      display: flex;
86      flex-direction: column;
87      gap: 6px;
88      margin-bottom: 10px;
89    }
90
91    label {
92      font-size: 12px;
93      color: var(--muted);
94      font-weight: 700;
95    }
96
97    input, select, textarea, button {
98      font: inherit;
99    }
100
101    input, select, textarea {
102      width: 100%;
103      padding: 10px 12px;
104      border-radius: 12px;
105      border: 1px solid rgba(255,255,255,0.18);
106      background: rgba(255,255,255,0.96);
107      color: #2b0000;
108      outline: none;
109    }
110
111    textarea {
112      min-height: 110px;
113      resize: vertical;
114    }
115
116    .wh-actions {
117      display: flex;
118      flex-wrap: wrap;
119      gap: 10px;
120      margin-top: 10px;
121    }
122
123    button {
124      border: 0;
125      border-radius: 12px;
126      padding: 10px 14px;
127      cursor: pointer;
128      background: #fff;
129      color: #7a0000;
130      font-weight: 700;
131    }
132
133    button.wh-secondary {
134      background: rgba(255,255,255,0.18);
135      color: var(--text);
136      border: 1px solid rgba(255,255,255,0.18);
137    }
138
139    .wh-preset-btns {
140      display: flex;
141      flex-wrap: wrap;
142      gap: 8px;
143      margin-bottom: 8px;
144    }
145
146    .wh-preset-btns button {
147      padding: 6px 12px;
148      font-size: 12px;
149      background: rgba(255,255,255,0.18);
150      color: var(--text);
151      border: 1px solid rgba(255,255,255,0.28);
152      border-radius: 999px;
153      font-weight: 700;
154      cursor: pointer;
155    }
156
157    .wh-preset-btns button:hover {
158      background: rgba(255,255,255,0.30);
159    }
160
161    .wh-stats {
162      display: grid;
163      grid-template-columns: repeat(3, minmax(0,1fr));
164      gap: 10px;
165    }
166
167    .wh-stat {
168      background: rgba(255,255,255,0.09);
169      border: 1px solid rgba(255,255,255,0.14);
170      border-radius: 14px;
171      padding: 14px;
172    }
173
174    .wh-stat .k {
175      font-size: 12px;
176      color: var(--muted);
177      margin-bottom: 6px;
178      font-weight: 700;
179    }
180
181    .wh-stat .v {
182      font-size: 24px;
183      font-weight: 700;
184      line-height: 1;
185    }
186
187    .wh-note {
188      margin-top: 12px;
189      font-size: 12px;
190      color: var(--muted);
191      line-height: 1.45;
192    }
193
194    .wh-tags {
195      display: flex;
196      flex-wrap: wrap;
197      gap: 8px;
198      margin-top: 8px;
199      justify-content: flex-end;
200    }
201
202    .wh-tag {
203      font-size: 12px;
204      background: rgba(255,255,255,0.12);
205      border: 1px solid rgba(255,255,255,0.12);
206      border-radius: 999px;
207      padding: 5px 8px;
208      color: var(--accent);
209    }
210
211    .wh-divider {
212      height: 1px;
213      background: rgba(255,255,255,0.14);
214      margin: 14px 0;
215    }
216
217    .wh-full {
218      grid-column: 1 / -1;
219    }
220
221    .wh-chart-label {
222      font-size: 11px;
223      font-weight: 700;
224      color: var(--muted);
225      letter-spacing: 0.06em;
226      text-transform: uppercase;
227      margin-bottom: 6px;
228      margin-top: 14px;
229    }
230
231    .wh-tc-svg {
232      width: 100%;
233      display: block;
234    }
235
236    .wh-dist-legend {
237      display: flex;
238      gap: 14px;
239      margin-bottom: 8px;
240      flex-wrap: wrap;
241    }
242
243    .wh-dist-legend span {
244      font-size: 11px;
245      color: var(--muted);
246      display: flex;
247      align-items: center;
248      gap: 5px;
249    }
250
251    .wh-dist-legend i {
252      display: inline-block;
253      width: 10px;
254      height: 10px;
255      border-radius: 2px;
256      flex-shrink: 0;
257    }
258
259    .wh-bar-wrap {
260      display: flex;
261      align-items: flex-end;
262      gap: 5px;
263      height: 130px;
264      margin-top: 4px;
265    }
266
267    .wh-bar-col {
268      display: flex;
269      flex-direction: column;
270      align-items: center;
271      flex: 1;
272      height: 100%;
273      justify-content: flex-end;
274      gap: 2px;
275    }
276
277    .wh-bar {
278      width: 100%;
279      border-radius: 4px 4px 0 0;
280      min-height: 2px;
281    }
282
283    .wh-bar-lbl {
284      font-size: 10px;
285      color: var(--muted);
286    }
287
288    .wh-bar-pct {
289      font-size: 10px;
290      font-weight: 700;
291      color: var(--text);
292      line-height: 1.2;
293    }
294
295    .wh-bar-cnt {
296      font-size: 9px;
297      color: var(--muted);
298      line-height: 1.2;
299    }
300
301    .wh-no-data {
302      font-size: 13px;
303      color: var(--muted);
304      padding: 10px 0;
305    }
306
307    .wh-approx-note {
308      font-size: 11px;
309      color: var(--muted);
310      margin-bottom: 8px;
311    }
312
313    @media (max-width: 900px) {
314      .wh-header {
315        align-items: flex-start;
316        flex-direction: column;
317      }
318      .wh-tags {
319        justify-content: flex-start;
320      }
321    }
322
323    @media (max-width: 640px) {
324      .wh-row, .wh-stats {
325        grid-template-columns: 1fr;
326      }
327      .wh-title {
328        font-size: 24px;
329      }
330    }
331
332    /* Draggable Collapsible Block Styles */
333    .blocks-container {
334      display: flex;
335      flex-direction: column;
336      gap: 16px;
337      margin-top: 16px;
338    }
339
340    .drag-block {
341      background: var(--card);
342      border: 1px solid var(--card-border);
343      border-radius: 16px;
344      box-shadow: var(--shadow);
345      backdrop-filter: blur(4px);
346      transition: opacity 0.2s ease, transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
347    }
348
349    .drag-block.dragging {
350      opacity: 0.4;
351      transform: scale(0.98);
352      border: 2px dashed rgba(255, 255, 255, 0.4);
353    }
354
355    .drag-block.drag-over {
356      border-color: #ffd9d9;
357      box-shadow: 0 0 15px rgba(255, 217, 217, 0.3);
358    }
359
360    .block-header {
361      display: flex;
362      align-items: center;
363      padding: 14px 18px;
364      border-bottom: 1px solid rgba(255, 255, 255, 0.08);
365      user-select: none;
366    }
367
368    .block-header.collapsible {
369      cursor: pointer;
370    }
371
372    .block-header h3 {
373      margin: 0;
374      font-size: 16px;
375      font-weight: 700;
376      flex: 1;
377    }
378
379    .drag-handle {
380      font-size: 18px;
381      color: var(--muted);
382      cursor: grab;
383      margin-right: 12px;
384      padding: 0 4px;
385    }
386
387    .drag-handle:active {
388      cursor: grabbing;
389    }
390
391    .collapse-toggle {
392      font-size: 10px;
393      color: var(--muted);
394      transition: transform 0.2s ease;
395      margin-left: 10px;
396    }
397
398    .block-header.collapsed .collapse-toggle {
399      transform: rotate(-90deg);
400    }
401
402    .block-header.collapsed {
403      border-bottom-color: transparent;
404    }
405
406    .block-content {
407      padding: 18px;
408      overflow: hidden;
409    }
410
411    .block-content.collapsed {
412      display: none;
413    }
414  </style>
415</head>
416<body>
417
418  <!-- ===== NAVIGATION ===== -->
419  <header class="site-header" id="top">
420    <nav class="nav-inner">
421      <a href="/" class="logo" aria-label="PerfectPlay Home">
422        <span class="logo-text">PerfectPlay</span>
423      </a>
424      <button class="hamburger" id="hamburger" aria-label="Toggle menu" aria-expanded="false">
425        <span></span><span></span><span></span>
426      </button>
427      <ul class="nav-links" id="nav-links">
428        <li><a href="/" class="nav-link">HOME</a></li>
429        <li><a href="/wong-halves" class="nav-link active">WONG HALVES</a></li>
430        <li><a href="/omega-2" class="nav-link">OMEGA 2</a></li>
431        <li><a href="/hi-opt-ii" class="nav-link">HI OPT II</a></li>
432        <li><a href="/hi-lo" class="nav-link">HI-LO</a></li>
433        <li><a href="/zen" class="nav-link">ZEN COUNT</a></li>
434        <li class="nav-dropdown-wrap">
435          <button class="more-btn" aria-label="More options">
436            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
437              <circle cx="12" cy="12" r="1"></circle>
438              <circle cx="19" cy="12" r="1"></circle>
439              <circle cx="5" cy="12" r="1"></circle>
440            </svg>
441          </button>
442          <ul class="dropdown-menu">
443            <li><a href="/wong-halves">WONG HALVES</a></li>
444            <li><a href="/omega-2">OMEGA 2</a></li>
445            <li><a href="/hi-opt-ii">HI OPT II</a></li>
446            <li><a href="/hi-lo">HI-LO</a></li>
447            <li><a href="/zen">ZEN COUNT</a></li>
448            <li><a href="/full-composition">FULL COMPOSITION</a></li>
449            <li><a href="/privacy">Privacy Policy</a></li>
450            <li class="dropdown-divider" style="border-top: 1px solid rgba(255,255,255,0.1); margin: 6px 0;"></li>
451            <li><a href="/" style="font-weight: 600; color: #fff;">English</a></li>
452            <li><a href="/zh">中文 (Mandarin)</a></li>
453            <li><a href="/fr">Français</a></li>
454            <li><a href="/ru">Русский</a></li>
455          </ul>
456        </li>
457      </ul>
458    </nav>
459  </header>
460
461  <div class="wh-wrap">
462    <!-- Header -->
463    <div class="wh-header">
464      <div>
465        <h2 class="wh-title">Perfectplay.dev Wong Halves</h2>
466        <div class="wh-sub">Fractional counting. Betting and insurance use granular TC rather than half-step or floored TC for better accuracy. half-step TC is displayed only as an extra reference.</div>
467      </div>
468      <div class="wh-tags">
469        <span class="wh-tag">2:+0.5</span><span class="wh-tag">3:+1</span><span class="wh-tag">4:+1</span><span class="wh-tag">5:+1.5</span>
470        <span class="wh-tag">6:+1</span><span class="wh-tag">7:+0.5</span><span class="wh-tag">8:0</span><span class="wh-tag">9:-0.5</span>
471        <span class="wh-tag">T/J/Q/K/A:-1</span>
472      </div>
473    </div>
474
475    <!-- Draggable Collapsible Blocks Container -->
476    <div class="blocks-container" id="blocks-container">
477      
478      <!-- Card Entry Block -->
479      <div class="drag-block" draggable="true" data-block-id="card-entry" id="block-card-entry">
480        <div class="block-header">
481          <span class="drag-handle">&#9776;</span>
482          <h3>Card Entry</h3>
483        </div>
484        <div class="block-content">
485          <div class="wh-field">
486            <label for="wh-cards">Cards seen</label>
487            <input id="wh-cards" type="text" placeholder="Example: 2 5 A T 9">
488          </div>
489          <div class="wh-row">
490            <div class="wh-field">
491              <label for="wh-decksTotal">Number of decks</label>
492              <input id="wh-decksTotal" type="number" min="1" max="12" step="1">
493            </div>
494            <div class="wh-field">
495              <label for="wh-shuffleAt">Shuffle when decks remaining &lt;=</label>
496              <input id="wh-shuffleAt" type="number" min="0" step="0.1">
497            </div>
498          </div>
499          <div class="wh-actions">
500            <button id="wh-add">Add</button>
501            <button id="wh-undo" class="wh-secondary">Undo last add</button>
502            <button id="wh-reset" class="wh-secondary">New shoe</button>
503          </div>
504          <div class="wh-note">10 becomes T. Undo uses a full stack, so repeated clicks walk back multiple previous adds.</div>
505        </div>
506      </div>
507
508      <!-- Live Stats Block -->
509      <div class="drag-block" draggable="true" data-block-id="live-stats" id="block-live-stats">
510        <div class="block-header collapsible" id="header-live-stats">
511          <span class="drag-handle">&#9776;</span>
512          <h3>Live Stats</h3>
513          <span class="collapse-toggle">&#9660;</span>
514        </div>
515        <div class="block-content" id="content-live-stats">
516          <div class="wh-stats">
517            <div class="wh-stat"><div class="k">Running count</div><div class="v" id="wh-rc"></div></div>
518            <div class="wh-stat"><div class="k">Decks remaining</div><div class="v" id="wh-dr"></div></div>
519            <div class="wh-stat"><div class="k">True count</div><div class="v" id="wh-tc"></div></div>
520            <div class="wh-stat"><div class="k">Half-step TC</div><div class="v" id="wh-tch"></div></div>
521            <div class="wh-stat"><div class="k">Recommended bet</div><div class="v" id="wh-bet"></div></div>
522            <div class="wh-stat"><div class="k">Insurance</div><div class="v" id="wh-ins" style="font-size:20px;"></div></div>
523          </div>
524        </div>
525      </div>
526
527      <!-- Relevant Settings Block -->
528      <div class="drag-block" draggable="true" data-block-id="relevant-settings" id="block-relevant-settings">
529        <div class="block-header collapsible" id="header-relevant-settings">
530          <span class="drag-handle">&#9776;</span>
531          <h3>Relevant Settings</h3>
532          <span class="collapse-toggle">&#9660;</span>
533        </div>
534        <div class="block-content" id="content-relevant-settings">
535          <div class="wh-row">
536            <div class="wh-field">
537              <label for="wh-tableMin">Table minimum</label>
538              <input id="wh-tableMin" type="number" min="1" step="1">
539            </div>
540            <div class="wh-field">
541              <label for="wh-tableMax">Table maximum</label>
542              <input id="wh-tableMax" type="number" min="1" step="1">
543            </div>
544          </div>
545          <div class="wh-field">
546            <label>How much to bet at each true count level</label>
547            <div class="wh-preset-btns">
548              <button id="wh-preset-1-8">Spread 1-8</button>
549              <button id="wh-preset-1-12">Spread 1-12</button>
550              <button id="wh-preset-1-16">Spread 1-16</button>
551            </div>
552            <textarea id="wh-customRamp"></textarea>
553          </div>
554          <div class="wh-note">Edit directly or tap a preset above to load it. Each line: TC&lt;=0:1, TC&gt;=1:2, TC&gt;=4:12 etc.</div>
555        </div>
556      </div>
557
558      <!-- History Stats Block -->
559      <div class="drag-block" draggable="true" data-block-id="history-stats" id="block-history-stats">
560        <div class="block-header collapsible" id="header-history-stats">
561          <span class="drag-handle">&#9776;</span>
562          <h3>History &amp; Stats</h3>
563          <span class="collapse-toggle">&#9660;</span>
564        </div>
565        <div class="block-content" id="content-history-stats">
566          <div id="wh-history-body"></div>
567        </div>
568      </div>
569
570    </div>
571  </div>
572
573  
573<script src="main.js"></script>
573
574  
574<script src="wong-halves.js"></script>
574
575</body>
576</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.