import tkinter as tk
import random
import math

# ---------------- CONFIG ----------------
TILE_SIZE = 20
WORLD_WIDTH = 300
WORLD_HEIGHT = 120

SCREEN_WIDTH = 25
SCREEN_HEIGHT = 15

root = tk.Tk()
root.title("Organic Rock Texture")

canvas = tk.Canvas(
    root,
    width=SCREEN_WIDTH*TILE_SIZE,
    height=SCREEN_HEIGHT*TILE_SIZE,
    bg="#050505"
)
canvas.pack()

# ---------------- MONDE ----------------
world = [[3 for _ in range(WORLD_WIDTH)] for _ in range(WORLD_HEIGHT)]

# ---------------- GROTTE ----------------
center_y = WORLD_HEIGHT // 2

for x in range(WORLD_WIDTH):
    curve = int(10 * math.sin(x * 0.015))
    thickness = 20 + random.randint(-2, 2)

    top = center_y - thickness + curve
    bottom = center_y + thickness + curve

    for y in range(WORLD_HEIGHT):
        if top < y < bottom:
            world[y][x] = 0

# ---------------- LISSAGE ----------------
def smooth():
    global world
    new = [row[:] for row in world]

    for y in range(1, WORLD_HEIGHT-1):
        for x in range(1, WORLD_WIDTH-1):

            if world[y][x] == 0:
                continue

            air = 0
            for dy in [-1,0,1]:
                for dx in [-1,0,1]:
                    if world[y+dy][x+dx] == 0:
                        air += 1

            if air >= 5:
                new[y][x] = 0

    world = new

for _ in range(5):
    smooth()

# ---------------- SPAWN ----------------
def find_spawn():
    for y in range(WORLD_HEIGHT//2):
        for x in range(WORLD_WIDTH):
            if world[y][x] == 0:
                return x,y
    return 10,10

spawn_x,spawn_y = find_spawn()

# ---------------- JOUEUR ----------------
player={"x":float(spawn_x),"y":float(spawn_y),"vx":0,"vy":0,"on_ground":False}
keys=set()

# ---------------- CAMERA ----------------
camera_x=0
camera_y=0

# ---------------- COLLISION ----------------
def solid(x,y):
    if x<0 or y<0 or x>=WORLD_WIDTH or y>=WORLD_HEIGHT:
        return True
    return world[int(y)][int(x)] != 0

def collides(x,y):
    return solid(x,y) or solid(x+0.9,y) or solid(x,y+0.9) or solid(x+0.9,y+0.9)

# ---------------- MOVE ----------------
def move():
    nx=player["x"]+player["vx"]
    if not collides(nx,player["y"]):
        player["x"]=nx

    player["vy"]+=0.05
    ny=player["y"]+player["vy"]

    if not collides(player["x"],ny):
        player["y"]=ny
        player["on_ground"]=False
    else:
        if player["vy"]>0:
            player["on_ground"]=True
        player["vy"]=0

# ---------------- CAMERA ----------------
def update_camera():
    global camera_x,camera_y
    camera_x += (player["x"]-camera_x-SCREEN_WIDTH/2)*0.08
    camera_y += (player["y"]-camera_y-SCREEN_HEIGHT/2)*0.08

# ---------------- LIGHT ----------------
def light(x,y):
    d=math.hypot(x-player["x"],y-player["y"])
    return max(0.15,min(1,1-d*0.06))

# ---------------- HASH BRUIT (ANTI MOTIF) ----------------
def hash_noise(x,y):
    n = x * 374761393 + y * 668265263
    n = (n ^ (n >> 13)) * 1274126177
    return (n & 0xFFFFFFFF) / 0xFFFFFFFF

# ---------------- TEXTURE ROCHE ORGANIQUE ----------------
def rock_color(x,y,l):

    n = hash_noise(x,y)

    # base grise
    base = 110 + int(n * 40)  # 110 → 150

    # micro variation locale
    micro = (hash_noise(x+5,y-3) - 0.5) * 20

    r = base + micro
    g = base + micro
    b = base + micro

    # léger accent bleu/gris selon bruit
    if n > 0.66:
        b += 10
    elif n < 0.33:
        r -= 10

    # lumière
    r=int(r*l)
    g=int(g*l)
    b=int(b*l)

    return f"#{int(r):02x}{int(g):02x}{int(b):02x}"

# ---------------- DRAW ----------------
def draw():
    canvas.delete("all")

    camx=int(camera_x)
    camy=int(camera_y)

    for y in range(SCREEN_HEIGHT):
        for x in range(SCREEN_WIDTH):

            wx=x+camx
            wy=y+camy

            if 0<=wx<WORLD_WIDTH and 0<=wy<WORLD_HEIGHT:

                if world[wy][wx]==0:
                    continue

                l=light(wx,wy)
                color=rock_color(wx,wy,l)

                canvas.create_rectangle(
                    x*TILE_SIZE,y*TILE_SIZE,
                    (x+1)*TILE_SIZE,(y+1)*TILE_SIZE,
                    fill=color,outline=""
                )

    px=(player["x"]-camx)*TILE_SIZE
    py=(player["y"]-camy)*TILE_SIZE

    canvas.create_rectangle(px,py,px+TILE_SIZE,py+TILE_SIZE,fill="white")

# ---------------- UPDATE ----------------
def update():

    if "q" in keys: player["vx"]=-0.3
    elif "d" in keys: player["vx"]=0.3
    else: player["vx"]=0

    if "space" in keys and player["on_ground"]:
        player["vy"]=-0.6

    move()
    update_camera()
    draw()

    root.after(16,update)

# ---------------- INPUT ----------------
def key_down(e): keys.add(e.keysym.lower())
def key_up(e): keys.discard(e.keysym.lower())

root.bind("<KeyPress>",key_down)
root.bind("<KeyRelease>",key_up)

update()
root.mainloop()
