Make the run to the net and back a double tap
Oliver: "das Vorlaufen und Zurücklaufen sollte durch einen Doppeltipp ausgelöst werden". It replaces v374's flick-length rule: the long up-flick is only the deep ball again, the long down-flick only the lob. While his own ball flies there is nothing to hit, so a tap there is not a swing. Two inside 0.35 s take him in to the net from the back, or back from the net. "TO THE NET" or "BACK" pops under him. An incoming ball keeps every tap a swing, so the two meanings never share a moment. After his own serve it is serve and volley. The short-ball approach stays automatic. Measured: the base ladder is unchanged, and following the ball in still pays against pushers and costs against big hitters. Three tests replace v374's two; v376. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bb72a01a3e
commit
48d1069e40
7 files changed
+107
-37
No files matched your search
+7
-3
@@ -93,7 +93,7 @@ const med = a => { const s = [...a].sort((x, y) => x - y); return s.length ? s[M
|
||||
// 120 ms tap), and plays the game a little — a lob or a pass against a net man, the odd drop when
|
||||
// the opponent hangs back. BOT=dist is the original fixed-distance tapper with random flicks.
|
||||
const HUMAN = (process.env.BOT || 'human') === 'human';
|
||||
const ATTACK = Number(process.env.ATTACK || 0); // share of baseline shots played as the attack (long up-flick)
|
||||
const ATTACK = Number(process.env.ATTACK || 0); // share of baseline shots followed in: a deep flick, then a DOUBLE TAP
|
||||
const JIT = Number(process.env.JIT ?? 60) / 1000, LAG = 7;
|
||||
const gauss = () => Math.sqrt(-2 * Math.log(1 - Math.random())) * Math.cos(2 * Math.PI * Math.random());
|
||||
const netx = { attacks: 0, smash: 0, smashWon: 0, lobbed: 0, open: null, p0: 0 };
|
||||
@@ -108,7 +108,7 @@ function humanAim() {
|
||||
const away = rz && rz.x > 0 ? -1 : 1; // the side he is not on
|
||||
if (oz < TUNE.netFrom) return r < 0.4 ? sw(0, 1, 150) : sw(away, -0.3, 120); // net man: lob him or pass him
|
||||
if (oz > COURT.netZ + 0.5 && Math.abs(P.z - COURT.netZ) < COURT.netZ - 1.5 && r < 0.15) return sw(0, 1, 50); // drop
|
||||
if (ATTACK && Math.abs(P.z - COURT.netZ) >= TUNE.netFrom && r < ATTACK) return sw(away * 0.3, -1, 130); // the attack: follow it in
|
||||
if (ATTACK && Math.abs(P.z - COURT.netZ) >= TUNE.netFrom && Math.random() < ATTACK) { bot.dbl = true; return sw(away * 0.3, -1, 130); } // the attack
|
||||
if (r < 0.45) return sw(away, -0.2, 110); // to the open side
|
||||
if (r < 0.65) return sw(0, -1, 80); // deep through the middle
|
||||
return null; // a plain tap
|
||||
@@ -162,6 +162,8 @@ for (const rung of RUNGS) {
|
||||
}
|
||||
}
|
||||
if (i === bot.fire) { G.swipe = bot.swipe; keyPressed('Space', bot.swipe ? 0 : LAG / 60, !!bot.swipe); }
|
||||
if (bot.dbl && ball.lastHit === 'P' && ball.active) { bot.dbl = false; bot.taps = [i + 4, i + 12]; } // follow it in: the double tap
|
||||
if (bot.taps && bot.taps.includes(i)) keyPressed('Space', 0.1);
|
||||
}
|
||||
else if (G.phase === 'rally' && ball.active && ball.lastHit === 'O') {
|
||||
const d = Math.hypot(ball.x - P.x, (ball.z - P.z) * 0.8);
|
||||
@@ -178,7 +180,9 @@ for (const rung of RUNGS) {
|
||||
const px0 = P.x, pz0 = P.z, tg0 = P.tgt;
|
||||
if (process.env.PROBE && lh === 'O' && bot.land && P.swingT >= 0) bot.land.sw = P.swingT, bot.land.d = Math.hypot(ball.x - P.x, (ball.z - P.z) * 0.8), bot.land.y = ball.y, bot.land.bb = ball.bounces;
|
||||
update(DT);
|
||||
if (lh !== 'P' && ball.lastHit === 'P' && ball.active) { if (ball.approach === 'P' && !G.wasServe) netx.attacks++; if (ball.smash) { netx.smash++; netx.open = 'smash'; } }
|
||||
if (lh !== 'P' && ball.lastHit === 'P' && ball.active && ball.smash) { netx.smash++; netx.open = 'smash'; }
|
||||
if (ball.lastHit === 'P' && ball.approach === 'P' && !netx.wasIn) netx.attacks++; // a run in (the double tap, or a short ball)
|
||||
netx.wasIn = ball.lastHit === 'P' && ball.approach === 'P';
|
||||
if (lh === 'P' && ball.lastHit === 'O' && ball.active && ball.soft && Math.abs(P.z - COURT.netZ) < TUNE.netFrom) netx.lobbed++;
|
||||
if (netx.open && (G.phase !== 'rally' || !ball.active)) { const d0 = score.pts[0] - netx.p0; if (d0 > 0) netx.smashWon++; netx.open = null; }
|
||||
if (netx.open === null) netx.p0 = score.pts[0];
|
||||
|
||||
Reference in new issue
Block a user