We have released RumiCar Simulator v10.4.0. The release notes below are also available on GitHub.
v10.4.0
Fixed ordinary words being rejected when posting questions and suggestions, the display after changing a setting while driving, the order of the standings, missing HTML escaping, keyboard access, how often loop() is called in live driving, and errors of learning programs (Stage BL; the formulas of the driving physics are untouched — the result of the shipped official sample race is unchanged; the official sample race’s verifyHash e9f1da0b and the frozen hashes f0–f3 are the same as before, and so is the output of the shipped sample programs). Live driving (▶) and the behaviour of your program may change — check (6) and (7) below. (1) Banned-word check for questions and suggestions — English words are now matched as whole words (a letter or digit next to it makes it a different word), and Japanese words of two characters or fewer no longer match when the neighbouring characters are of the same script. v10.3.0 rejected posts such as “カスタム車種を作りたい”, “cockpit view が欲しい”, “Essex のコースを作った”, “Dickens” and “die hard な設定” before sending; they now pass. Abusive expressions are still rejected (the list grew from 39 to 54 words, and forms with small kana or a long-vowel mark such as “バカッ!” and “アホー!” are rejected too). Compound words written without a break can still pass, and some harmless sentences are still rejected (such as “少しね” and “勢いを殺す”); these are listed at the top of moderate.js. (2) Changing settings while driving — changing the course, tire, gear, suspension, steering, brake, wear, physics mode or driving area while driving stops the run, but in v10.3.0 the car card stayed stuck in the code view and did not return to the editor. It now stops the same way as pressing ■. (3) Standings and races — in the standings while driving, among cars on the same lap the car that crossed the line first is now listed higher (v10.3.0 put the car with the shorter time on the current lap, i.e. the car behind, higher). On mountain-pass courses, cars that have finished are ordered by shorter total time. In races where the same author submitted several entries, the 📖 showcase and the 👻 opponent took that author’s first entry; they now look the entry up by name. The 👻 re-run now drives with the race’s physics, test-run and wear settings (v10.3.0 used the physics currently selected on screen with no test run and no wear, so 👻 results can change). Re-run verification of a race with an entry containing an unreadable value no longer stops silently; it shows “⚠ Could not re-run: an entry of this race has a value that cannot be read”. (4) HTML escaping — some values of your own and posted car types and of race results were put into HTML without escaping in the car-type table, the edit form and the 🏆 details (writing <img src=x onerror=…> in a value ran a script). Races and posts that contain values that cannot be turned into a string (such as {"toString":1}) no longer stop the 🏆 details, re-run verification, 🍴, 🏅 or 👻 midway; when they cannot go on, they show a single “[Error] …” line. (5) Display and keyboard access — the background of the large program editor was transparent, so the screen behind showed through; it now has the same background as the other dialogs (in the glass theme it is semi-transparent like the other dialogs, and the screen behind is dimmed and blurred by 2 px). The labels of the 3D preview of mountain-pass courses are now in English in English mode. The file pickers (⬆, Import JSON and 📥 Import backup) can now be reached with Tab and opened with Space (v10.3.0 allowed only the mouse). (6) loop() in live driving — live driving (▶) now calls loop() 20 times per second of sim time (the on-screen clock). v10.3.0 called it at most once per frame, so when a frame was longer than 0.05 sim seconds it was called less often (about 10 times per second at 30 fps × speed 3×; even at 60 fps × 3× it dropped by the frames longer than 16.7 ms, measured 17.4–18.2 times per second), and the missed calls piled up as a “debt” that was paid by calling it on every frame after the screen became light again or the speed was set back to 1× (about 60 times per second). Now the sim time of a frame is cut into slices of 0.05 s, and for each slice “the loop() of each car that is due → physics integration of that slice” is repeated (at most 3 calls of loop() per car per frame; conditions you can select on screen never reach this cap). The second and later loop() calls see the pose and sensors after the previous slice, and delay() takes effect instead of being swallowed by the debt. The debt of a negative delay() beyond one period is discarded (a program that sometimes calls a negative delay is called a different number of times even at 60 fps × 1×). Because loop() is called at the start of the slice in which it falls due, the interval between calls is not constant (longer than 0 and at most 0.1 s + delay, 0.05 s + delay on average). When a frame is longer than 0.05 sim seconds (at a low frame rate, or when a frame takes longer than 16.7 ms at the default speed 3×), the trajectory of live driving differs from v10.3.0 even with the same program — waiting at the wall for the rest of the step after hitting it, backing up by auto recovery, waiting for the start, turning a wrong-way car around and lap detection now work per slice, so the runs part from the moment the car touches a wall, recovers or is turned around. When every frame is 0.05 sim seconds or shorter (60 fps at speed 1× or 2×, for example) nothing changes. Official races (🏁) use the deterministic engine at a fixed 60 Hz and are not affected. (7) Errors of learning programs (py and C) — Forms that ran without error in v10.3.0 but raise an error in v10.4.0 (mostly errors in python3 too): random.choice([]), random.choice("") and random.choice of a number or a dict (v10.3.0 returned no value; print showed an empty line), and len(a, b) and random.choice(a, b) (v10.3.0 used only the first argument; the arguments are counted only for calls written in a py or C program — JavaScript programs and forms where another function makes the call, such as ["ab", "c"].map(len), still use only the first one as in v10.3.0). Forms whose error message or line changed: len(None) and len(5) (Japanese-only without a line number → “len() needs a list, tuple, str or dict (None has no length)” in the display language with a line number), len() and random.choice() (Japanese only / a JS error → “len() takes exactly one argument (0 given)”, and the same form for random.choice()), random.choice(None) (JS’s “Cannot read properties of null …” → “random.choice() needs a list, tuple or str …”), str()/print() of a deeply nested list in a while True: program or outside a function (JS’s “Maximum call stack size exceeded” without a line number → “Nesting is too deep (the call stack of the runtime ran out). …” with a line number), recursion that runs out of stack inside def loop() or before the 200-level limit (a level count that did not match reality, such as “(the nesting reached 1 levels)” → the same “Nesting is too deep”; the message at the 200-level limit is unchanged), the line of an error raised in a loop condition (the condition of a while from the second check on, the condition and update of C’s for, the condition of do-while: the line of the last statement of the body → the line of that loop), the line of an error raised in the condition of elif/else if (the line of the first if → that line), and a step-limit (infinite loop) error whose last step was a function call inside one of those conditions (→ the line of that loop, elif or else if; loops whose condition calls no function report the same line as before). The truth value of a dict (if d:) and the value of len(d) are the same as in v10.3.0. What has not changed: the formulas of the driving physics, the deterministic engine of official races (🏁) (programs using the forms in (7) now stop with an error), the output of the shipped sample programs, and the display of the current position when there is no error. The fixes and the remaining differences are described in the physics model explanation §0 (calls to loop()) and §9 (the language semantics of learning programs). In addition, the number of permanent verification gates went from 80 to 81 (wf_bl1_ui.mjs).
Verifying this release yourself
git clone https://github.com/RumiCar-group/RumiCar-Simulator.git
cd RumiCar-Simulator
node wf_run_all.mjs # the full assertion-gate suiteThe suite runs from a fresh clone with no dependencies beyond Node.js.
The real-browser checks under browser/ additionally need npm install and a display.
