# -*- coding: utf-8 -*-
"""
Experimentul 6 — Controlul in timp real al unui rover pe Marte (DIRD, sectiunea XI,
Fig. 12: "Real-Time Earth Control of Mars Rover").

Joc-demonstratie a problemei de latenta:
  * legatura RADIO (viteza luminii): comenzile si imaginea video sosesc cu
    intarziere (4-20 minute in realitate; comprimata aici la cateva secunde);
  * legatura CUANTICA NELOCALA (ipotetica, daca semnalizarea nelocala ar exista):
    comenzile ajung practic instantaneu, "inapoi pe firul timpului", iar
    operatorul de pe Pamant conduce roverul in realitate virtuala.

Conduceti roverul cu sagetile stanga/dreapta pana la steag, ocolind pietrele.
Ceea ce vedeti pe ecran este imaginea VIDEO INTARZIATA (asa cum o vede operatorul);
cu legatura radio, roverul real este deja in alta parte decat il vedeti.

Nota de fizica: teorema de ne-semnalizare interzice o astfel de legatura in QM
standard; jocul arata doar DE CE ar fi fost atat de dorita (DIRD, Fig. 12).
"""
import sys
import math
import random
import tkinter as tk
from tkinter import ttk

W, H = 640, 460
DT = 50            # ms pas de joc
VITEZA = 2.2       # px / pas
ROT = 0.09         # rad / pas


class AppRover:
    def __init__(self, root):
        self.root = root
        root.title("Exp. 6 — Rover pe Marte in timp real (DIRD Fig. 12)")

        ctl = ttk.Frame(root, padding=8)
        ctl.pack(side=tk.LEFT, fill=tk.Y)
        ttk.Label(ctl, text="Pamant -> Marte",
                  font=("Segoe UI", 12, "bold")).pack(pady=(0, 6))

        ttk.Label(ctl, text="Legatura de comunicatie:").pack(anchor="w")
        self.v_link = tk.StringVar(value="radio")
        ttk.Radiobutton(ctl, text="Radio (viteza luminii)",
                        variable=self.v_link, value="radio",
                        command=self.reset).pack(anchor="w")
        ttk.Radiobutton(ctl, text="Cuantica nelocala (ipotetica)",
                        variable=self.v_link, value="cuantic",
                        command=self.reset).pack(anchor="w")

        ttk.Label(ctl, text="Intarziere radio dus [s]\n(demo; real: 4-20 min):").pack(
            anchor="w", pady=(8, 0))
        self.v_delay = tk.DoubleVar(value=2.0)
        ttk.Scale(ctl, from_=0.5, to=6, variable=self.v_delay).pack(fill=tk.X)

        ttk.Button(ctl, text="Restart", command=self.reset).pack(fill=tk.X, pady=8)
        self.lbl = ttk.Label(ctl, text="", font=("Consolas", 10), justify="left")
        self.lbl.pack(anchor="w", pady=6)

        ttk.Label(ctl, wraplength=220, justify="left", foreground="#555", text=(
            "Sageti STANGA / DREAPTA = viraj.\n\n"
            "Pe ecran vedeti imaginea video asa cum soseste pe Pamant. "
            "Cu legatura radio, si comenzile, si imaginea sunt intarziate: "
            "roverul real (conturul palid) e deja in alta parte. "
            "Cu legatura cuantica nelocala (daca ar exista!) ati conduce "
            "in timp real.\n\n"
            "QM standard interzice asta (teorema de ne-semnalizare).")).pack(anchor="w")

        self.cv = tk.Canvas(root, width=W, height=H, bg="#b5512e",
                            highlightthickness=0)
        self.cv.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
        root.bind("<Left>", lambda e: self.comanda(-1))
        root.bind("<Right>", lambda e: self.comanda(+1))

        self.reset()
        self.ruleaza()
        if "--test" in sys.argv:
            root.after(2500, root.destroy)

    # ------------------------------------------------------------------
    def reset(self):
        random.seed(7)
        self.t = 0.0
        self.x, self.y, self.dir = 60.0, H - 60.0, -0.5
        self.vir = 0
        self.coada_cmd = []     # (t_sosire_pe_marte, viraj)
        self.istoric = []       # (t, x, y, dir) pentru video intarziat
        self.pietre = [(random.uniform(120, W - 120), random.uniform(60, H - 60),
                        random.uniform(14, 26)) for _ in range(9)]
        self.steag = (W - 60, 60)
        self.stare = "joc"
        self.mesaj = ""

    def delay(self):
        return 0.02 if self.v_link.get() == "cuantic" else self.v_delay.get()

    def comanda(self, viraj):
        if self.stare != "joc":
            return
        # comanda pleaca de pe Pamant ACUM si ajunge pe Marte dupa delay
        self.coada_cmd.append((self.t + self.delay(), viraj))

    # ------------------------------------------------------------------
    def ruleaza(self):
        if self.stare == "joc":
            self.t += DT / 1000.0
            # comenzile sosite pe Marte
            self.vir = 0
            ramase = []
            for (ts, v) in self.coada_cmd:
                if ts <= self.t:
                    self.vir = v
                else:
                    ramase.append((ts, v))
            self.coada_cmd = ramase
            self.dir += self.vir * ROT * 3
            self.x += VITEZA * math.cos(self.dir)
            self.y += VITEZA * math.sin(self.dir)
            self.istoric.append((self.t, self.x, self.y, self.dir))
            # coliziuni (pe Marte, in timp real)
            if not (15 < self.x < W - 15 and 15 < self.y < H - 15):
                self.stare = "crash"
                self.mesaj = "A iesit de pe teren! Restart."
            for (px, py, pr) in self.pietre:
                if math.hypot(self.x - px, self.y - py) < pr + 10:
                    self.stare = "crash"
                    self.mesaj = "Roverul a lovit o piatra! Restart."
            if math.hypot(self.x - self.steag[0], self.y - self.steag[1]) < 24:
                self.stare = "castigat"
                self.mesaj = f"Misiune reusita in {self.t:.1f} s!"
        self.deseneaza()
        self.root.after(DT, self.ruleaza)

    def poz_video(self):
        """Starea roverului asa cum o vede operatorul (video intarziat)."""
        tv = self.t - self.delay()
        for (ts, x, y, d) in reversed(self.istoric):
            if ts <= tv:
                return x, y, d
        return self.istoric[0][1:] if self.istoric else (self.x, self.y, self.dir)

    def deseneaza_rover(self, x, y, d, culoare, contur=""):
        p = [(x + 14 * math.cos(d), y + 14 * math.sin(d)),
             (x + 11 * math.cos(d + 2.5), y + 11 * math.sin(d + 2.5)),
             (x + 11 * math.cos(d - 2.5), y + 11 * math.sin(d - 2.5))]
        self.cv.create_polygon(p, fill=culoare, outline=contur or culoare)

    def deseneaza(self):
        self.cv.delete("all")
        for (px, py, pr) in self.pietre:
            self.cv.create_oval(px - pr, py - pr, px + pr, py + pr,
                                fill="#7a3a20", outline="#5a2a15", width=2)
        fx, fy = self.steag
        self.cv.create_line(fx, fy + 18, fx, fy - 18, fill="white", width=3)
        self.cv.create_polygon(fx, fy - 18, fx + 22, fy - 11, fx, fy - 4,
                               fill="#2ca02c")
        # roverul REAL (palid) si imaginea VIDEO (plina)
        self.deseneaza_rover(self.x, self.y, self.dir, "#e8c3b2")
        vx, vy, vd = self.poz_video()
        self.deseneaza_rover(vx, vy, vd, "#ffd400", "black")
        leg = ("legatura CUANTICA — practic instantanee"
               if self.v_link.get() == "cuantic"
               else f"legatura RADIO — intarziere {self.delay():.1f} s dus")
        self.cv.create_text(10, 12, anchor="w", fill="white",
                            font=("Segoe UI", 10, "bold"),
                            text=f"t = {self.t:5.1f} s   {leg}")
        self.cv.create_text(10, 32, anchor="w", fill="#ffd400",
                            text="galben = ce vede operatorul   pal = roverul real",
                            font=("Segoe UI", 9))
        if self.stare != "joc":
            self.cv.create_text(W / 2, H / 2, text=self.mesaj, fill="white",
                                font=("Segoe UI", 18, "bold"))
        self.lbl.config(text=f"timp: {self.t:6.1f} s\nstare: {self.stare}")


if __name__ == "__main__":
    root = tk.Tk()
    AppRover(root)
    root.mainloop()
