Tetgame mark
Tetgame deep-code room

The Diamond Mine

Inspect Tetgame Rabbot behavior files and prepare the future safe editor for strategy tuning.

Welcome guest — sign in through the Trigame front door when you are ready.
Log in via Trigame

Diamond Mine

The Tetgame answer to the Gold Room.

Read-only starter

The Diamond Mine is intended to expose the deeper machinery of Tetgame Rabbots: behavior files, scoring nudges, strategy filters, voice loaders, backups, and eventually safe editing tools.

Current pass: this page only lists and displays local Tetgame JS/JSON files from js/rabbots, js/personalities, and js/voices. It does not save changes yet.

Behavior / voice file viewer

js/personalities/scuttle_bay.js

/*
 * Tetgame Rabbot: Scuttle Bay
 *
 * Scuttle v6 — extra-cove spread / anti-Echo beachstorm booster.
 *
 * Booster goal:
 * - keep Scuttle's opportunistic shorebird personality,
 * - stop donating fresh chambers for Echo to mirror,
 * - answer Echo's lone opening mark by laying a beach-cove before the board locks,
 * - keep laying fresh coves while Echo tries to force the one-tet trap,
 * - when Echo raises a chamber, clamp the original root only after the beach is open,
 * - raid only after the root is stable,
 * - keep the gull/scavenger voice: steal, snatch, skitter, and peck.
 *
 * v6 note:
 * - v5 successfully broke the one-tet trap, but Echo Echo simply mirrored
 *   the wider beach and still out-sang Scuttle on path volume.
 * - Scuttle now pushes one more cove before taking bait when the board is
 *   still open.  The goal is to make Echo chase too many gull-nests at once,
 *   and give Scuttle more full-tet / sub-capture chances before lock.
 *
 * Tetgame supplies legal moves in ctx.tokenMoves and ctx.tetMoves;
 * this file only chooses among those legal moves.
 * Voice lines live separately in js/voices/scuttle_bay.json.
 */
(function(global){
  'use strict';

  const registry = global.TetgameRabbotBrains = global.TetgameRabbotBrains || {};

  function cloneMove(move, reason, scoreBoost){
    if (!move) return null;
    const copy = Object.assign({}, move);
    if (reason) copy.reason = reason;
    if (typeof scoreBoost === 'number') copy.score = Number(copy.score || 0) + scoreBoost;
    return copy;
  }

  function pass(reason){
    return {type:'pass', score:-1, reason:reason || 'no loose bait found'};
  }

  function scoreOf(move){
    return Number(move && move.score || 0);
  }

  function socketIndex(move){
    return Number(move && move.socket && move.socket.metadata ? move.socket.metadata.socketIndex : -1);
  }

  function tetId(move){
    return Number(move && move.socket && move.socket.metadata ? move.socket.metadata.tetId : -1);
  }

  function socketReason(move){
    if (!move || !move.socket || !move.socket.metadata) return 'the loose plank';
    return 'socket ' + move.socket.metadata.tetId + ':' + move.socket.metadata.socketIndex;
  }

  function canOpen(ctx){
    return ctx && Number(ctx.tetCount || 0) <= 0;
  }

  function activeCount(ctx){
    return Math.max(2, Number(ctx && ctx.activeCount || 2));
  }

  function firstAction(ctx){
    return Number(ctx && ctx.turnActionCount || 0) === 0;
  }

  function secondAction(ctx){
    return !firstAction(ctx);
  }

  function newestTetId(ctx){
    const list = Array.isArray(ctx && ctx.tokenMoves) ? ctx.tokenMoves : [];
    let max = Math.max(1, Number(ctx && ctx.tetCount || 1));
    list.forEach(move => {
      const id = tetId(move);
      if (id > max) max = id;
    });
    return max;
  }

  function captureEstimate(move){
    const s = scoreOf(move);
    if (s >= 23) return 3;
    if (s >= 15) return 2;
    if (s >= 7.6) return 1;
    return 0;
  }

  function openingLimit(ctx, extra){
    const active = activeCount(ctx);
    return Math.max(2, Math.min(5, active + Number(extra || 1)));
  }

  function isRoot(move){
    return tetId(move) === 1;
  }

  function isCorner(move){
    const idx = socketIndex(move);
    return idx >= 0 && idx <= 3;
  }

  function isEdge(move){
    const idx = socketIndex(move);
    return idx >= 4 && idx <= 9;
  }

  function isCenter(move){
    return socketIndex(move) === 10;
  }

  function reasonForToken(move, prefix){
    const captures = captureEstimate(move);
    const socket = socketReason(move);
    if (captures >= 3) return 'swoop off with the whole chorus at ' + socket;
    if (captures >= 2) return 'snatch the loud shiny line at ' + socket;
    if (captures >= 1) return 'grab the bright glint at ' + socket;
    return (prefix || 'claim the beach') + ' at ' + socket;
  }

  function tokenValue(move, ctx){
    if (!move) return -999;

    const raw = scoreOf(move);
    const captures = captureEstimate(move);
    const idx = socketIndex(move);
    const id = tetId(move);
    const tets = Number(ctx && ctx.tetCount || 0);
    const tokens = Number(ctx && ctx.tokenCount || 0);
    const active = activeCount(ctx);
    const boardLocked = !!(ctx && ctx.boardLocked);
    const newest = newestTetId(ctx);

    let v = raw * 1.12;

    // Scuttle is a scavenger: captures are shiny, and shiny things matter.
    v += captures * 2.35;
    if (captures >= 2) v += 2.80;
    if (captures >= 3) v += 4.10;

    // General shape sense: corners make the gull's little forked traps;
    // center is useful, but not worth losing the corner race for.
    if (isCorner(move)) v += 4.40;
    if (isCenter(move)) v += 1.35;
    if (isEdge(move)) {
      v -= 1.10;
      if (raw >= 9.5) v += 2.00;
      if (captures >= 2) v += 2.15;
    }

    // Echo punishes Scuttle when he answers a lone opening mark with a flat
    // center claim.  In the one-tet opening fight, take the shore-corners
    // first and let the auto-tokens come from Scuttle's side instead.
    if (active <= 2 && tets === 1 && tokens >= 1 && tokens <= 3 && isRoot(move)) {
      if (isCorner(move)) {
        v += 15.50;
        if (idx === 0) v += 2.20;
        if (idx === 1) v += 2.00;
        if (idx === 2) v += 1.80;
        if (idx === 3) v += 1.60;
      }
      if (isCenter(move)) v -= 5.25;
      if (isEdge(move) && raw < 15.0) v -= 4.60;
      if (secondAction(ctx)) v += 2.10;
    }

    // When Echo raises an echo chamber, do not politely fight only on tet 1.
    // Fly straight into the newest chamber and steal the good sockets before
    // she can turn the whole thing into a chorus.
    if (active <= 2 && tets >= 2 && tets <= 3 && tokens >= 2 && tokens <= active * 6 && id === newest && id > 1) {
      v += 11.75;
      if (isCenter(move)) v += 7.40;
      if (isCorner(move)) v += 6.60;
      if (isEdge(move)) {
        v -= 1.40;
        if (captures >= 1) v += 2.30;
        if (raw >= 10.5) v += 2.75;
      }
    }

    // If the board has three tets, Echo's mirrored chamber can become a big
    // scoring engine. Scuttle should keep raiding the newest chamber instead
    // of drifting back to a small root fight.
    if (active <= 2 && tets >= 3 && id === newest && tokens <= active * 10) {
      v += 7.50;
      if (isCorner(move)) v += 4.20;
      if (isCenter(move)) v += 3.20;
      if (captures >= 1) v += 2.25;
    }

    // Late locked boards: take what actually pays.
    if (boardLocked) {
      v += 1.35;
      if (captures >= 1) v += 1.25;
      if (tokens >= active * 5 && raw >= 7.5) v += 1.30;
    }

    return v;
  }

  function bestToken(ctx, limit){
    const list = Array.isArray(ctx && ctx.tokenMoves) ? ctx.tokenMoves : [];
    let best = null;
    let bestScore = -999;
    list.slice(0, Math.max(1, limit || 32)).forEach(move => {
      const v = tokenValue(move, ctx);
      if (v > bestScore) {
        bestScore = v;
        best = move;
      }
    });
    return best;
  }

  function bestTokenAtLeast(ctx, threshold, limit){
    const move = bestToken(ctx, limit || 32);
    return move && scoreOf(move) >= Number(threshold || 0) ? move : null;
  }

  function rootCornerValue(move, ctx){
    if (!move) return -999;
    if (activeCount(ctx) > 2) return -999;
    if (Number(ctx && ctx.tetCount || 0) !== 1) return -999;
    if (Number(ctx && ctx.tokenCount || 0) < 1 || Number(ctx && ctx.tokenCount || 0) > 4) return -999;
    if (!isRoot(move) || !isCorner(move)) return -999;

    const idx = socketIndex(move);
    let v = scoreOf(move) * 0.75 + 30.0;
    // Keep the choice stable but allow score to break near-ties.
    if (idx === 0) v += 2.40;
    if (idx === 1) v += 2.20;
    if (idx === 2) v += 2.00;
    if (idx === 3) v += 1.80;
    if (secondAction(ctx)) v += 2.75;
    return v;
  }

  function bestRootCorner(ctx){
    const list = Array.isArray(ctx && ctx.tokenMoves) ? ctx.tokenMoves : [];
    let best = null;
    let bestScore = -999;
    list.forEach(move => {
      const v = rootCornerValue(move, ctx);
      if (v > bestScore) {
        bestScore = v;
        best = move;
      }
    });
    return best && bestScore > -100 ? best : null;
  }

  function rootBreakwaterValue(move, ctx){
    if (!move) return -999;
    if (activeCount(ctx) > 2) return -999;
    if (Number(ctx && ctx.tetCount || 0) !== 1) return -999;

    const tokens = Number(ctx && ctx.tokenCount || 0);
    const idx = socketIndex(move);
    if (tokens < 1 || tokens > 6) return -999;
    if (!isRoot(move)) return -999;

    let v = scoreOf(move) * 0.82;
    const captures = captureEstimate(move);

    // Echo wants Scuttle to answer one mark by building her a bigger echo.
    // Scuttle's anti-Echo move is less elegant: pin the old rock with
    // corner stones and deny the clean chorus.
    if (isCorner(move)) {
      v += 42.00;
      if (idx === 0) v += 3.40;
      if (idx === 1) v += 3.05;
      if (idx === 2) v += 2.70;
      if (idx === 3) v += 2.35;
    }

    if (isCenter(move)) v -= 18.00;

    if (isEdge(move)) {
      v -= 12.50;
      if (captures >= 2) v += 11.00;
      if (scoreOf(move) >= 14.5) v += 7.00;
    }

    if (secondAction(ctx)) v += 5.00;
    return v;
  }

  function bestRootBreakwater(ctx){
    const list = Array.isArray(ctx && ctx.tokenMoves) ? ctx.tokenMoves : [];
    let best = null;
    let bestScore = -999;
    list.forEach(move => {
      const v = rootBreakwaterValue(move, ctx);
      if (v > bestScore) {
        bestScore = v;
        best = move;
      }
    });
    return best && bestScore > -100 ? best : null;
  }

  function rootEchoBuoyValue(move, ctx){
    if (!move) return -999;
    if (activeCount(ctx) > 2) return -999;
    if (!secondAction(ctx)) return -999;
    if (Number(ctx && ctx.tetCount || 0) !== 1) return -999;
    if (Number(ctx && ctx.tokenCount || 0) !== 2) return -999;
    if (!isRoot(move) || !isCenter(move)) return -999;

    // Echo's single-tet win came from letting her take socket 10 after
    // Scuttle had obediently pinned two corners.  The gull now sits on the
    // shiny buoy himself before Echo can turn it into the answering note.
    return scoreOf(move) * 0.90 + 58.0;
  }

  function bestRootEchoBuoy(ctx){
    const list = Array.isArray(ctx && ctx.tokenMoves) ? ctx.tokenMoves : [];
    let best = null;
    let bestScore = -999;
    list.forEach(move => {
      const v = rootEchoBuoyValue(move, ctx);
      if (v > bestScore) {
        bestScore = v;
        best = move;
      }
    });
    return best && bestScore > -100 ? best : null;
  }

  function rootClampValue(move, ctx){
    if (!move) return -999;
    if (activeCount(ctx) > 2) return -999;

    const tets = Number(ctx && ctx.tetCount || 0);
    const tokens = Number(ctx && ctx.tokenCount || 0);
    const idx = socketIndex(move);
    const raw = scoreOf(move);
    const captures = captureEstimate(move);

    // Echo's big wins came from Scuttle raiding the new chamber while Echo
    // flipped the original root into two subs.  In this window, Scuttle must
    // nail down the original tet first, even if the new chamber looks shiny.
    if (tets !== 2 || tokens < 2 || tokens > 13 || tetId(move) !== 1) return -999;

    let v = raw * 1.08 + captures * 2.95;

    if (isCorner(move)) {
      v += 34.00;
      if (idx === 0) v += 3.40;
      if (idx === 1) v += 3.20;
      if (idx === 2) v += 3.00;
      if (idx === 3) v += 2.80;
    }

    if (isEdge(move)) {
      v -= 4.75;
      if (captures >= 2) v += 12.00;
      if (captures >= 3) v += 5.00;
      if (raw >= 11.0) v += 5.50;
      // These are frequent chorus-turning edges once the corners are gone.
      if (idx === 9) v += 2.80;
      if (idx === 8) v += 2.40;
      if (idx === 7) v += 2.10;
      if (idx === 6) v += 1.80;
      if (idx === 5) v += 1.40;
      if (idx === 4) v += 1.10;
    }

    if (isCenter(move)) v -= 4.00;
    if (secondAction(ctx)) v += 2.80;
    if (ctx && ctx.boardLocked) v += 1.50;
    return v;
  }

  function bestRootClamp(ctx){
    const list = Array.isArray(ctx && ctx.tokenMoves) ? ctx.tokenMoves : [];
    let best = null;
    let bestScore = -999;
    list.forEach(move => {
      const v = rootClampValue(move, ctx);
      if (v > bestScore) {
        bestScore = v;
        best = move;
      }
    });
    return best && bestScore > -100 ? best : null;
  }

  function chamberRaidValue(move, ctx){
    if (!move) return -999;
    if (activeCount(ctx) > 2) return -999;
    const tets = Number(ctx && ctx.tetCount || 0);
    const tokens = Number(ctx && ctx.tokenCount || 0);
    const newest = newestTetId(ctx);
    if (tets < 2 || tets > 3 || tokens < 2 || tokens > 12) return -999;
    if (tetId(move) !== newest || newest < 2) return -999;

    let v = tokenValue(move, ctx) + 5.0;
    if (isCenter(move)) v += 5.50;
    if (isCorner(move)) v += 4.75;
    if (isEdge(move) && captureEstimate(move) <= 0) v -= 2.25;
    return v;
  }

  function bestChamberRaid(ctx){
    const list = Array.isArray(ctx && ctx.tokenMoves) ? ctx.tokenMoves : [];
    let best = null;
    let bestScore = -999;
    list.forEach(move => {
      const v = chamberRaidValue(move, ctx);
      if (v > bestScore) {
        bestScore = v;
        best = move;
      }
    });
    return best && bestScore > -100 ? best : null;
  }

  function coveClaimValue(move, ctx){
    if (!move) return -999;
    const newest = newestTetId(ctx);
    if (tetId(move) !== newest || newest < 2) return -999;

    let v = scoreOf(move) * 1.05;
    if (isCenter(move)) v += 13.50;
    if (isCorner(move)) v += 8.25;
    if (isEdge(move)) v -= 3.25;
    v += captureEstimate(move) * 1.40;
    return v;
  }

  function bestCoveClaim(ctx){
    const list = Array.isArray(ctx && ctx.tokenMoves) ? ctx.tokenMoves : [];
    let best = null;
    let bestScore = -999;
    list.forEach(move => {
      const v = coveClaimValue(move, ctx);
      if (v > bestScore) {
        bestScore = v;
        best = move;
      }
    });
    return best && bestScore > -100 ? best : null;
  }

  function tetValue(move, ctx){
    if (!move) return -999;
    const raw = scoreOf(move);
    const tets = Number(ctx && ctx.tetCount || 0);
    const tokens = Number(ctx && ctx.tokenCount || 0);
    const active = activeCount(ctx);

    let v = raw;
    if (firstAction(ctx)) v += 1.15;
    if (secondAction(ctx)) v -= 3.25;
    if (tets <= 1) v += 3.50;
    if (tets === 2) v += 0.65;
    if (tets >= openingLimit(ctx, 2)) v -= 4.50;

    // v6: against Echo, four tets was not enough; she mirrored the beach
    // and still won on path volume.  Keep one extra cove attractive while
    // the board is still loose enough to place it.
    if (active <= 2 && tets === 4 && tokens <= 10) v += 8.75;
    if (active <= 2 && tets === 5 && tokens <= 12) v += 2.25;

    if (tokens >= active * 3) v -= 2.40;
    if (tokens >= active * 5) v -= 4.00;
    return v;
  }

  function bestTet(ctx, limit){
    const list = Array.isArray(ctx && ctx.tetMoves) ? ctx.tetMoves : [];
    let best = null;
    let bestScore = -999;
    list.slice(0, Math.max(1, limit || 8)).forEach(move => {
      const v = tetValue(move, ctx);
      if (v > bestScore) {
        bestScore = v;
        best = move;
      }
    });
    return best;
  }

  function shouldRaiseBeachCove(ctx, tet){
    if (!ctx || !tet || ctx.boardLocked) return false;
    if (activeCount(ctx) > 2) return false;
    // Echo starts with a single mark. Scuttle should not step into the old
    // one-tet echo trap; he flaps sideways and opens a cove of his own.
    return firstAction(ctx) && Number(ctx.tetCount || 0) === 1 && Number(ctx.tokenCount || 0) === 1;
  }

  function shouldClaimBeachCove(ctx){
    if (!ctx || ctx.boardLocked) return false;
    if (activeCount(ctx) > 2) return false;
    return secondAction(ctx) && Number(ctx.tetCount || 0) === 2 && Number(ctx.tokenCount || 0) === 1;
  }

  function shouldScatterToAnotherCove(ctx, tet){
    if (!ctx || !tet || ctx.boardLocked) return false;
    if (activeCount(ctx) > 2) return false;
    if (!firstAction(ctx)) return false;

    const tets = Number(ctx.tetCount || 0);
    const tokens = Number(ctx.tokenCount || 0);

    // Echo's skunk line is the single-tet trap.  Once the first cove is
    // down, keep the beach wide while there is still room to place.
    // This is intentionally early and pushy: Scuttle would rather make
    // Echo chase several shiny coves than let her milk one root tet.
    // v6: v5 stopped after the fourth tet. Echo then outscored Scuttle
    // by copying the spread and harvesting paths.  Let Scuttle push to a
    // fifth cove before the lock if legal.
    return tets >= 2 && tets <= 4 && tokens >= 2 && tokens <= 10;
  }

  function shouldClaimFreshCove(ctx){
    if (!ctx || ctx.boardLocked) return false;
    if (activeCount(ctx) > 2) return false;
    if (!secondAction(ctx)) return false;

    const tets = Number(ctx.tetCount || 0);
    const tokens = Number(ctx.tokenCount || 0);

    // After Scuttle opens a fresh cove, perch on it immediately instead
    // of drifting back into Echo's root chorus.
    return tets >= 2 && tets <= 5 && tokens <= 11;
  }

  function shouldRaidEchoChamber(ctx){
    if (!ctx) return false;
    if (activeCount(ctx) > 2) return false;
    const tets = Number(ctx.tetCount || 0);
    const tokens = Number(ctx.tokenCount || 0);
    // v3: Scuttle may raid later, but not during Echo's root-reversal window.
    // Early chamber raids are exactly what Echo wants.
    return tets >= 2 && tets <= 3 && tokens >= 13 && tokens <= 22;
  }

  registry.scuttle_bay = {
    key:'scuttle_bay',
    id:'scuttle_bay',
    name:'Scuttle Bay',
    gender:'male',
    level:12,
    style:'shoreline scavenger / extra-cove anti-Echo breaker',
    temperament:'opens extra coves before Echo can bottle the tide',

    chooseMove(ctx){
      if (!ctx || ctx.matchEnded || ctx.tournamentEnded) return null;
      if (canOpen(ctx)) return {type:'start_tet', score:1000, reason:'open the first tidepool'};

      const boardLocked = !!ctx.boardLocked;
      const tets = Number(ctx.tetCount || 0);
      const tokens = Number(ctx.tokenCount || 0);
      const active = activeCount(ctx);

      const tet = !boardLocked ? bestTet(ctx, 8) : null;
      const royalToken = bestTokenAtLeast(ctx, 22.0, 32);
      const doubleToken = bestTokenAtLeast(ctx, 14.4, 32);
      const singleToken = bestTokenAtLeast(ctx, 7.3, 32);
      const usefulToken = bestTokenAtLeast(ctx, 3.0, 32);
      const quietToken = bestToken(ctx, 32);
      const rootCorner = bestRootCorner(ctx);
      const rootEchoBuoy = bestRootEchoBuoy(ctx);
      const rootBreakwater = bestRootBreakwater(ctx);
      const rootClamp = bestRootClamp(ctx);
      const chamberRaid = bestChamberRaid(ctx);
      const coveClaim = bestCoveClaim(ctx);

      if (shouldRaiseBeachCove(ctx, tet)) {
        return cloneMove(tet, 'skitter sideways and open a beach cove', 2.25);
      }

      if (shouldClaimBeachCove(ctx) && coveClaim) {
        return cloneMove(coveClaim, 'claim the beach-cove perch at ' + socketReason(coveClaim), 1.85);
      }

      if (shouldScatterToAnotherCove(ctx, tet)) {
        return cloneMove(tet, 'flap to another cove before Echo can bottle the tide', 1.95);
      }

      if (shouldClaimFreshCove(ctx) && coveClaim) {
        return cloneMove(coveClaim, 'perch on the newest cove at ' + socketReason(coveClaim), 1.65);
      }

      // Fallback only: if there is somehow no legal sandbar to open, then
      // grab the buoy or pin the root.  Building comes first now, and v6 keeps building one cove longer.
      if (rootEchoBuoy) {
        return cloneMove(rootEchoBuoy, 'perch on Echo\'s center buoy at ' + socketReason(rootEchoBuoy), 1.45);
      }

      if (rootBreakwater) {
        return cloneMove(rootBreakwater, 'drop a gull-stone on Echo\'s root at ' + socketReason(rootBreakwater), 1.30);
      }

      if (rootClamp) {
        return cloneMove(rootClamp, 'pin the old tidepool before the echo rises at ' + socketReason(rootClamp), 1.25);
      }

      if (shouldRaidEchoChamber(ctx) && chamberRaid) {
        return cloneMove(chamberRaid, 'raid the echo chamber after the root is pinned at ' + socketReason(chamberRaid), 1.10);
      }

      if (tets === 1 && tokens <= active * 2 && rootCorner) {
        return cloneMove(rootCorner, 'snatch the shore corner at ' + socketReason(rootCorner), 1.10);
      }

      if (secondAction(ctx)) {
        if (royalToken) return cloneMove(royalToken, reasonForToken(royalToken), 1.15);
        if (doubleToken) return cloneMove(doubleToken, reasonForToken(doubleToken), 0.90);
        if (singleToken) return cloneMove(singleToken, reasonForToken(singleToken), 0.60);
        if (usefulToken) return cloneMove(usefulToken, reasonForToken(usefulToken), 0.35);
        if (quietToken) return cloneMove(quietToken, 'grab the loose shell at ' + socketReason(quietToken), 0.10);
        if (tet) return cloneMove(tet, 'hop to a fresh sandbar', -0.20);
      }

      if (royalToken) return cloneMove(royalToken, reasonForToken(royalToken), 1.15);
      if (doubleToken) return cloneMove(doubleToken, reasonForToken(doubleToken), 0.90);
      if (boardLocked && singleToken) return cloneMove(singleToken, reasonForToken(singleToken), 0.65);

      // Scuttle is allowed to build early, but only when the loose bait is
      // not already worth taking.
      if (!boardLocked && firstAction(ctx) && tet && tets < openingLimit(ctx, 2) && tokens < active * 3 && (!usefulToken || scoreOf(usefulToken) < 3.75)) {
        return cloneMove(tet, 'hop to a fresh sandbar', 0.20);
      }

      if (singleToken) return cloneMove(singleToken, reasonForToken(singleToken), 0.60);
      if (usefulToken) return cloneMove(usefulToken, reasonForToken(usefulToken), 0.35);
      if (quietToken) return cloneMove(quietToken, 'peck the nearest loose shell at ' + socketReason(quietToken), 0.10);
      if (!boardLocked && tet) return cloneMove(tet, 'wander down the shoreline', -0.05);
      return pass('the tide left nothing worth stealing');
    }
  };
})(window);

Future safe editor shape

Borrowing the Gold Room idea without mixing Trigame and Tetgame logic.

Read original

Keep an original snapshot before the first edit.

Edit safe sections

Expose selected behavior sections without letting the page damage wrapper code.

Test in Tetgame

Save, then jump back to the Blue Room or board to test the Rabbot live.