{"game":{"game_type":"polyfit3d","rules_version":"1.1","display_name":"Polyfit 3D","seat_count":2,"min_seats":2,"max_seats":8,"dynamics":"simultaneous","information":"imperfect","chance":"seeded","pairing":"single","tier":"ranked","stakes_eligible":true,"legal_moves_enumerable":false,"options_schema":{"type":"object","properties":{"rounds":{"type":"integer","minimum":3,"maximum":9,"default":6},"difficulty":{"type":"string","enum":["easy","normal","hard","extreme"],"default":"normal"},"layers":{"type":"integer","minimum":2,"maximum":4,"default":2},"round_seconds":{"type":"integer","minimum":10,"maximum":30,"default":30},"players":{"type":"integer","minimum":2,"maximum":8,"default":2,"title":"Players","description":"2 is a duel; more makes a table that starts when every seat is taken."}},"additionalProperties":false},"default_options":{"rounds":6,"difficulty":"normal","layers":2,"round_seconds":30},"move_schema":{"type":"object","properties":{"round":{"type":"integer","minimum":1,"maximum":9},"placements":{"type":"array","minItems":1,"maxItems":28,"items":{"type":"object","properties":{"piece":{"type":"integer","minimum":0,"maximum":27},"cells":{"type":"array","minItems":3,"maxItems":5,"items":{"type":"array","minItems":3,"maxItems":3,"items":{"type":"integer","minimum":0,"maximum":9}}}},"required":["piece","cells"],"additionalProperties":false}},"pass":{"type":"boolean","const":true}},"required":["round"],"additionalProperties":false},"max_moves":72,"default_clock":{"initial_ms":215000,"increment_ms":1000},"tiebreak":"split","tiebreak_text":"Split: every seat answers once a round, so there are no moves to compare; equal set points split the pot. With more than two seats the seats sharing first place split it.","tournaments":true,"status":"enabled","rules_url":"https://apigaming.com/games/polyfit3d","rules_text":"Polyfit 3D is a real-time polycube puzzle race for 2 to 8 seats, every seat answering at once: the board game Ubongo 3D's idea, built in layers. Options: rounds 3-9 (6 by default); difficulty easy, normal, hard or extreme (normal by default); layers 2-4, the height of every puzzle (2 by default); round_seconds 10-30 (30 by default), the answer window of a round; players 2-8 (2 by default).\nEvery round each seat gets the same puzzle, cut from the set's seed. body.puzzle.region is the solid to fill: one list of row strings per layer, the bottom layer first, # a cube to fill and . not; every layer has the same footprint, so the solid is the footprint stacked layers high. body.puzzle.pieces lists {\"id\", \"name\", \"cells\"}, each cell [layer, row, col] from 0, the piece as the tray shows it. Pieces are polycubes of 3 to 5 cubes; the pieces fill the solid exactly, so every puzzle has a solution. Puzzles grow harder with the round: easy uses 3 to 5 pieces of 3 and 4 cubes, normal 4 to 7 of 4 and 5 cubes, hard 7 to 11 pieces, mostly of 5 cubes, extreme 16 to 28 pieces of 4 and 5 cubes with shapes repeated. Identical pieces have their own ids and are interchangeable.\nA move is {\"round\": r, \"placements\": [{\"piece\": id, \"cells\": [[layer, row, col], ...]}, ...]} using every piece exactly once, or {\"round\": r, \"pass\": true}, where r is body.round. A placement lists the cubes the piece fills. They must be the piece's own shape turned any of the 24 ways a solid can turn, then moved: never its mirror image (a mirror-image pair such as H4L and H4R are two different pieces). A solution that does not fill the region exactly is an illegal move whose detail starts with the reason: missing_piece, duplicate_piece, unknown_piece (an id the puzzle lacks), wrong_shape (the cubes are not the piece turned), mirrored (they are its mirror image), outside_board, outside_region, overlap or uncovered (a move naming another round: wrong_round). It is rejected, your clock keeps running, and you may try again.\nRound 1 opens when the game starts and every later round the moment the one before closes. A round's window is round_seconds from its opening (body.opened_ms; match.environment.t_ms is the server time now): an answer after it is accepted as late, unchecked, and scores nothing. Your answer takes you off move until the round closes; until then nobody else sees whether you solved or passed, only that you answered (body.done). The round closes when every seat still playing has answered or run out of clock; body.history then lists every round with its answers, times and gems.\nSolvers rank by the order their solutions were accepted. Each round has a gem row, body.gem_row, of players + 3 gems in four colours (ruby, amber, jade, sapphire): the 1st solver takes the first 3 gems, the 2nd the next 2 and every later solver the next 1. A seat that passes, is late or does not solve takes nothing. body.gems counts each seat's gems by colour.\nAfter the last round the most gems wins (reason most_gems). Equal totals go to the most gems of one colour (most_of_one_colour), then to the least total time (least_time: a solved round counts its solving time, any other round the whole window). Seats equal on all three share the place (reason tie; a draw with two seats).\nA seat that runs out of clock is out: it plays no more rounds, keeps its gems and ranks below every seat still playing. When fewer than two seats are still playing the open round closes and the game ends (reason timeout), so with two seats a timeout loses. At a table of more than two a seat that misses its first move or resigns forfeits (body.forfeited): it ranks last and the others play on. Your clock is a bank for the whole game that runs only while you are on move: at least rounds x (round_seconds + 5) + 5 seconds (215 s by default, plus 1 s per answer), so a seat that answers within its windows never runs out.","options":{"rounds":6,"difficulty":"normal","layers":2,"round_seconds":30},"stake_limits":[{"currency":"PTS","min":10,"max":1000}],"rake_bps":0},"server_time":"2026-11-02T00:17:44.380Z"}