Files

63 lines
1.9 KiB
Python

import json
import math
DEFAULT_STATE = '{"version": 1, "high_score": 0, "last_score": 0, "best_wave": 1}'
def parse_game_state(raw):
"""Read the JSON written by the browser game; bad or missing data falls back to zeros."""
try:
data = json.loads(raw or "{}")
except (TypeError, ValueError):
data = {}
if not isinstance(data, dict):
data = {}
def as_int(key, default):
value = data.get(key, default)
# bool is a subclass of int: reject it explicitly
if isinstance(value, bool) or not isinstance(value, (int, float)):
return default
if isinstance(value, float) and not math.isfinite(value): # json.loads accepts NaN/Infinity
return default
return max(0, int(value))
return {
"high_score": as_int("high_score", 0),
"last_score": as_int("last_score", 0),
"best_wave": max(1, as_int("best_wave", 1)),
}
class IsulionSpaceInvaders:
"""
A small Space Invaders game played inside the node (see web/space_invaders.js).
The browser stores scores in the hidden ``game_state`` widget; executing the
node outputs them, so a session's best score can feed a prompt or a seed.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"game_state": ("STRING", {"default": DEFAULT_STATE}),
}
}
RETURN_TYPES = ("INT", "INT", "STRING")
RETURN_NAMES = ("high_score", "last_score", "summary")
FUNCTION = "report"
CATEGORY = "Isulion/Games"
OUTPUT_NODE = True
def report(self, game_state):
state = parse_game_state(game_state)
summary = (
f"High score: {state['high_score']} | Last score: {state['last_score']} "
f"| Best wave: {state['best_wave']}"
)
return {
"ui": {"summary": [summary]},
"result": (state["high_score"], state["last_score"], summary),
}