from typing import Any
import duck
+
+class TM_ND_A:
+ """
+ TM_ND_A
+
+ TM Tape Machine
+ ND Non-destructive (no cell deletion)
+ A Addressed head
+
+ Contract:
+ - Head always on a valid cell.
+ - User must check can_step(n) before step(n).
+ """
+
+ # ----------------------------------------------------------------------
+ def __init__(self ,tape: Any):
+ # minimal requirement: length, getitem, setitem
+ duck.require(duck.class_of(tape) ,"__len__" ,"__getitem__" ,"__setitem__")
+
+ # synthetic extent() if tape lacks it
+ if not duck.has(tape ,"extent"):
+ tape.extent = lambda: len(tape) - 1
+
+ # synthetic clone() if tape lacks it
+ if not duck.has(tape ,"clone"):
+ def _default_clone(src=tape):
+ return src.__class__(src[:])
+ tape.clone = _default_clone
+
+ self._tape = tape
+ self._head: int = 0
+
+ # ----------------------------------------------------------------------
+ # topology
+ def extent(self) -> int: return self._tape.extent()
+ def tape(self) -> Any: return self._tape
+ def where(self) -> int: return self._head
+
+ # ----------------------------------------------------------------------
+ # absolute-position tests
+ def on_leftmost(self ,k: int = 0) -> bool:
+ return self._head == 0 + k
+
+ def on_rightmost(self ,k: int = 0) -> bool:
+ return self._head == self.extent() - k
+
+ # ----------------------------------------------------------------------
+ # motion
+ def can_step(self ,n: int = 1) -> bool:
+ nxt = self._head + n
+ return 0 <= nxt <= self.extent()
+
+ def step(self ,n: int = 1) -> None:
+ self._head += n
+
+ # ----------------------------------------------------------------------
+ # data transfer
+ def copy_from(self ,n: int = 0) -> Any:
+ return self._tape[self._head + n]
+
+ def copy_to(self ,value: Any ,n: int = 0) -> None:
+ self._tape[self._head + n] = value
+
+ # ----------------------------------------------------------------------
+ # structural changes (append, no drop)
+ def append(self ,value: Any ,n: int = 1) -> None:
+ """
+ Append cells left or right without deletion.
+ n > 0 -> append right n times
+ n < 0 -> append left |n| times
+ """
+ if n > 0:
+ for _ in range(n):
+ idx = self.extent() + 1
+ self._tape.append(value)
+ elif n < 0:
+ for _ in range(-n):
+ self._tape.insert(0 ,value)
+ self._head += 1 # head shifts right because new 0 inserted
+
+ # ----------------------------------------------------------------------
+ # entanglement: share tape, copy head only
+ def entangle(self) -> "TM_ND_A":
+ tm = object.__new__(TM_ND_A)
+ tm._tape = self._tape
+ tm._head = self._head
+ return tm
+
+ # ----------------------------------------------------------------------
+ # clone: duplicate tape and head
+ def clone(self) -> "TM_ND_A":
+ new = object.__new__(TM_ND_A)
+ new._tape = self._tape.clone()
+ new._head = self._head
+ return new
+
+
+# ----------------------------------------------------------------------
+if __name__ == "__main__":
+ # simple smoke test
+ tape = [1 ,2 ,3]
+ tm = TM_ND_A(tape)
+ print("extent =", tm.extent())
+ print("copy_from =", tm.copy_from())
+ tm.step(1)
+ tm.copy_to(99)
+ print("tape =", tm.tape())
+ tm.append(7 ,1)
+ print("after append right =", tm.tape())
+ tm.append(8 ,-1)
+ print("after append left =", tm.tape(), "head =", tm.where())
+ ent = tm.entangle()
+ clo = tm.clone()
+ print("entangle tape is tm.tape?", ent.tape() is tm.tape())
+ print("clone tape is tm.tape?", clo.tape() is tm.tape())
+
+#!/usr/bin/env python3
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+
+from __future__ import annotations
+from typing import Any
+import duck
+
class TM_ND_A:
"""
TM_ND_A