Dev.to WebDev 🛠 Dev 👁 0 📖 2 min read

Building a K-pop ticketing game — and fixing a one-point scoring bug

I built TicketKST, a browser game that recreates the pressure of booking K-pop concert tickets. Players wait for the sale to open, click into a queue, type a captcha, and then have 30 seconds to select seats. Requests i

I built TicketKST, a browser game that recreates the pressure of booking K-pop concert tickets.

Players wait for the sale to open, click into a queue, type a captcha, and then have 30 seconds to select seats. Requests include adjacent seats, aisle seats, and seats within a budget. Other simulated fans keep buying seats while you choose.

The game uses a fictional venue and does not book real tickets.

You can try it here: https://ticketkst.com

The frontend is vanilla JavaScript, HTML, and CSS. The backend uses Flask and SQLite.

One surprisingly small implementation detail caused the score shown in the browser to disagree with the leaderboard.

JavaScript and Python don't always round the same way

Each completed seat request earns points based on seat quality and a combo multiplier.

Consider a request worth 645 base points with a 2.5× multiplier:

Math.round(645 * 2.5)
// 1613

The original Python calculation used:

round(645 * 2.5)
# 1612

Python's built-in round() uses ties-to-even rounding, while JavaScript's Math.round() resolves this positive halfway value upward.

Both calculations looked reasonable on their own. Together, they produced a one-point discrepancy.

For the game's nonnegative point values, the server now uses:

import math

def round_points(value):
    return math.floor(value + 0.5)

The result screen also uses the server's saved score once the response arrives.

Recalculating a score isn't enough

Another issue was what the server trusted.

Recalculating a total from client-reported success counts and seat-quality values still lets the client invent those inputs.

The updated version sends seat actions and their timestamps instead. The server reconstructs the daily hall and checks:

  • Whether the selected seats were available
  • Whether they matched the current request
  • Whether adjacent seats were actually together
  • How scheduled sell-outs affected availability
  • What score and combo followed from those actions

This validates the game state. It does not prove that a human made every move or eliminate automated play.

Testing both implementations together

The daily challenge gives everyone the same initial hall and requests for the same Korean date.

That makes consistency between the JavaScript simulation and Python replay important.

An offline test harness runs the actual JavaScript controller with a lightweight DOM and clock test double. It generates action transcripts, which are then replayed by Python.

Across 45 test rounds, the checks compare the initial hall, request sequence, outcomes, score, seat count, and best combo. The scenarios include delayed frames and the game's three surprise events.

These tests helped check the boundary between the two implementations, rather than testing each scoring function in isolation.

I'd be interested to hear how other developers handle this: do you replay browser-game actions on the server, share simulation code between environments, or make the server authoritative for every move?

Disclosure: AI tools assisted with implementation and drafting this article.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.