# I'm trying to make a game inspired by the puzzles of The Witness

**URL:** https://discourse.processing.org/t/im-trying-to-make-a-game-inspired-by-the-puzzles-of-the-witness/47747
**Category:** Coding Questions
**Tags:** homework
**Created:** [January 13, 2026, 6:24am UTC](https://discourse.processing.org/t/im-trying-to-make-a-game-inspired-by-the-puzzles-of-the-witness/47747 "2026-01-13T06:24:46Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Fluffy1oo](https://avatars.discourse-cdn.com/v4/letter/f/7ab992/32.png) [@Fluffy1oo](https://discourse.processing.org/u/Fluffy1oo)
#### Post date: [January 13, 2026, 6:24am UTC](https://discourse.processing.org/t/im-trying-to-make-a-game-inspired-by-the-puzzles-of-the-witness/47747/1 "2026-01-13T06:24:46Z")

</div>

f`rom p5 import run,createCanvas,noLoop,background,stroke,line,fill,noStroke,rect,strokeWeight,noFill,ellipse,point,mouseIsPressed`

_`# DÉFINITION DES NIVEAUX`_

`LEVELS = [`  
` {`  
` "grid": (4, 4), `_`# taille de la grille : 4 colonnes x 4 lignes`_  
` "start": (0, 0), `_`# nœud de départ`_  
` "end": (4, 4), `_`# nœud d'arrivée`_  
` "blocked": [(1,1),(2,1)],`_`# cases interdites`_  
` "symbols": [(0,2,'circle'), (3,1,'circle')]`_`# symboles à visiter avant l'arrivée`_  
` },`  
` {`  
` "grid": (5, 5),`  
` "start": (0, 4),`  
` "end": (4, 0),`  
` "blocked": [(2,2),(1,3)],`  
` "symbols": [(0,2,'circle'), (2,4,'circle')]`  
` },`  
` {`  
` "grid": (6, 6),`  
` "start": (0, 0),`  
` "end": (5, 5),`  
` "blocked": [(2,2),(3,3),(1,4)],`  
` "symbols": [(1,1,'circle'), (4,4,'circle')]`  
` }`  
`]`

_`# CONFIGURATION VISUELLE`_

`CELL = 80 `_`# taille d'une cellule`_  
`MARGIN = 40 `_`# marge autour de la grille pour le dessin`_  
`SNAP_RADIUS = CELL / 1.5 `_`# rayon pour “attraper” le nœud avec le clic`_

_`# VARIABLES DU JEU`_

`current_level = 0 `_`# niveau actuel`_  
`path = [] `_`# liste des nœuds visités pour le chemin`_  
`lines_drawn = set() `_`# lignes déjà tracées (pour ne pas repasser dessus)`_  
`game_finished = False`

_`# FONCTIONS UTILITAIRES`_

`def node_position(node):`  
` """`  
` Convertit un nœud (col, row) en coordonnées pixels pour l'affichage`  
` """`  
` x, y = node`  
` return MARGIN + x * CELL, MARGIN + y * CELL`

`def distance(x1, y1, x2, y2):`  
` """`  
` Calcul de la distance euclidienne entre deux points`  
` """`  
` return ((x1-x2)**2 + (y1-y2)**2)**0.5`

`def snap_to_node(mx, my, grid):`  
` """`  
` Retourne le nœud le plus proche du clic`  
` """`  
` closest = None`  
` min_dist = SNAP_RADIUS`  
` cols, rows = grid`  
` for x in range(cols+1):`  
` for y in range(rows+1):`  
` nx, ny = node_position((x, y))`  
` d = distance(mx, my, nx, ny)`  
` if d <= min_dist:`  
` closest = (x, y)`  
` min_dist = d`  
` return closest`

`def is_adjacent(a, b):`  
` """`  
` Vérifie si deux nœuds sont adjacents horizontalement ou verticalement`  
` """`  
` return abs(a[0]-b[0]) + abs(a[1]-b[1]) == 1`

`def node_blocked(node):`  
` """`  
` Vérifie si un nœud est dans la liste des blocs interdits`  
` """`  
` x, y = node`  
` return (x, y) in LEVELS[current_level].get('blocked', [])`

`def line_used(a, b):`  
` """`  
` Vérifie si une ligne entre deux nœuds a déjà été tracée`  
` """`  
` return ((a,b) in lines_drawn) or ((b,a) in lines_drawn)`

_`# CONFIGURATION DE LA FENÊTRE`_

`def setup():`  
` """`  
` Initialisation du canvas en fonction de la taille de la grille`  
` """`  
` cols, rows = LEVELS[current_level]["grid"]`  
` createCanvas(2*MARGIN + cols*CELL, 2*MARGIN + rows*CELL)`  
` noLoop() `_`# dessin manuel uniquement (rafraîchissement avec redraw())`_

`def draw_grid():`  
` """`  
` Dessine la grille principale`  
` """`  
` cols, rows = LEVELS[current_level]["grid"]`  
` stroke(80)`  
` for x in range(cols+1):`  
` line(MARGIN+x*CELL, MARGIN, MARGIN+x*CELL, MARGIN+rows*CELL)`  
` for y in range(rows+1):`  
` line(MARGIN, MARGIN+y*CELL, MARGIN+cols*CELL, MARGIN+y*CELL)`

`def draw_blocks():`  
` """`  
` Dessine les cases bloquées`  
` """`  
` fill(0)`  
` noStroke()`  
` for bx, by in LEVELS[current_level].get('blocked', []):`  
` rect(MARGIN+bx*CELL, MARGIN+by*CELL, CELL, CELL)`

`def draw_symbols():`  
` """`  
` Dessine les symboles (ex: cercles) que le joueur doit visiter`  
` """`  
` symbols = LEVELS[current_level].get('symbols', [])`  
` strokeWeight(8)`  
` for x, y, kind in symbols:`  
` nx, ny = node_position((x, y))`  
` if kind=='circle':`  
` stroke(0,0,255)`  
` noFill()`  
` ellipse(nx, ny, 20, 20)`  
` strokeWeight(1)`

`def draw_points():`  
` """`  
` Dessine les points de départ (vert) et d'arrivée (rouge)`  
` """`  
` sx, sy = LEVELS[current_level]["start"]`  
` ex, ey = LEVELS[current_level]["end"]`  
` strokeWeight(10)`  
` stroke(0,255,0)`  
` px, py = node_position((sx, sy))`  
` point(px, py)`  
` stroke(255,0,0)`  
` px, py = node_position((ex, ey))`  
` point(px, py)`  
` strokeWeight(1)`

`def draw_path():`  
` """`  
` Dessine le chemin jaune tracé par le joueur`  
` """`  
` stroke(255,255,0)`  
` strokeWeight(6)`  
` for i in range(len(path)-1):`  
` a = path[i]`  
` b = path[i+1]`  
` x1, y1 = node_position(a)`  
` x2, y2 = node_position(b)`  
` line(x1, y1, x2, y2)`  
` strokeWeight(1)`

_`# INTERACTION : CLICS`_  
_`# DESSIN`_

`def draw():`  
` """`  
` Dessine la grille, les blocs, les symboles, les points de départ/arrivée et le chemin`  
` """`  
` background(30)`  
` global path, lines_drawn, current_level, game_finished`  
` if game_finished:`  
` fill(255)`  
` textSize(32)`  
` textAlign(CENTER, CENTER)`  
` text("JEU TERMINÉ", width/2, height/2)`  
` return`

` draw_grid()`  
` draw_blocks()`  
` draw_symbols()`  
` draw_path()`  
` draw_points()`

` `  
` `  
` if mouseIsPressed:`

` if game_finished:`  
` return`

` `_`# détecte le nœud le plus proche du clic`_  
` node = snap_to_node(mouseX, mouseY, LEVELS[current_level]["grid"])`  
` if node is None:`  
` return`

` `_`# si début du chemin`_  
` if not path and node == LEVELS[current_level]["start"]:`  
` path.append(node)`  
` lines_drawn = set()`  
` redraw()`  
` return`

` `_`# si on a déjà commencé le chemin`_  
` elif path:`  
` last = path[-1]`

` `_`# clic sur l'arrivée`_  
` if node == LEVELS[current_level]["end"]:`  
` `_`# vérifier que tous les symboles ont été visités`_  
` symbols = LEVELS[current_level].get('symbols', [])`  
` visited = set(path)`  
` all_symbols = all((x,y) in visited for x,y,_ in symbols)`  
` if not all_symbols:`  
` print("Vous devez passer sur tous les symboles !")`  
` return`  
` `_`# niveau terminé : passer au niveau suivant`_  
` current_level += 1`  
` path = []`  
` lines_drawn = set()`  
` if current_level >= len(LEVELS):`  
` game_finished = True`  
` redraw()`  
` return`

` `_`# clic sur nœud adjacent valide`_  
` elif is_adjacent(last, node) and not node_blocked(node) and not line_used(last, node):`  
` path.append(node)`  
` lines_drawn.add((last, node))`  
` redraw()`  
` `  
`run()`

Well, no matter how hard I try, the level shows, but when I try clicking on a node, it just doesn’t do anything.

---

<div class="post-metadata">

### Author: ![neill](https://avatars.discourse-cdn.com/v4/letter/n/edb3f5/32.png) [@neill](https://discourse.processing.org/u/neill)
#### Post date: [January 13, 2026, 6:41am UTC](https://discourse.processing.org/t/im-trying-to-make-a-game-inspired-by-the-puzzles-of-the-witness/47747/2 "2026-01-13T06:41:26Z")

</div>

Hello!  
I’m not too familiar with your setup (is it the native p5 library in python?) and don’t have it set up here, but here are two things I notice:

1. You have called `noLoop()` in `setup()` so the `draw()` will only be called _once_.

The mouse-pressed logic you have in `draw()` will only be run _once_, right at the start, _not_ throughout the game. So when you click, nothing is listening.

When you aren’t using a draw loop, it’s common to add a `mouse_pressed` function _outside_ of draw, which will be called _any_ time the mouse is pressed.

If I guess correctly the library you’re using, `mouse_pressed` is documented [here](https://p5.readthedocs.io/en/latest/reference/input.html?highlight=mouse_pressed).

1. Your code refers to mouseX and mouseY, which are correct names for the global variables in p5 in javascript but in your environment those should be mouse\_x and mouse\_y. As documented [here](https://p5.readthedocs.io/en/latest/reference/input.html#mouse-x-mouse-y). I could be wrong about that - again it depends on your environment.

I hope those help to get you started!

---

<div class="post-metadata">

### Author: ![neill](https://avatars.discourse-cdn.com/v4/letter/n/edb3f5/32.png) [@neill](https://discourse.processing.org/u/neill)
#### Post date: [January 13, 2026, 6:51am UTC](https://discourse.processing.org/t/im-trying-to-make-a-game-inspired-by-the-puzzles-of-the-witness/47747/3 "2026-01-13T06:51:02Z")

</div>

Also, I _think_ the correct category for this post is [p5py](https://discourse.processing.org/c/p5py/27)

…because this current category (“p5.js”) is for p5 with _javascript_, not python.

It’s not a big deal, I think! But if you don’t get much help here, you can try there instead, where there may be more python programmers!

---

<div class="post-metadata">

### Author: ![Fluffy1oo](https://avatars.discourse-cdn.com/v4/letter/f/7ab992/32.png) [@Fluffy1oo](https://discourse.processing.org/u/Fluffy1oo)
#### Post date: [January 13, 2026, 6:58am UTC](https://discourse.processing.org/t/im-trying-to-make-a-game-inspired-by-the-puzzles-of-the-witness/47747/5 "2026-01-13T06:58:45Z")

</div>

Thanks for the help, but it’s said that it uses p5.js

---

<div class="post-metadata">

### Author: ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)
#### Post date: [January 13, 2026, 8:09am UTC](https://discourse.processing.org/t/im-trying-to-make-a-game-inspired-by-the-puzzles-of-the-witness/47747/6 "2026-01-13T08:09:36Z")

</div>

Is it using PyScript + p5js by chance?

> [@ASCII visualization issue](https://discourse.processing.org/t/ascii-visualization-issue/42041/11):
>
> Just converted my 2 Python Mode sketches to run on just PyScript w/o any packages. [“Unicode Letters Test”](https://PyScript.com/view/37e29c80-c433-4dca-a8bc-4b7207b089a8/f540a5ff-ca53-4e5a-b149-a61df207cd01/latest) is using library p5\*js while [“Unicode Chars Test”](https://PyScript.com/view/37e29c80-c433-4dca-a8bc-4b7207b089a8/9c2d93cb-4168-45d9-a58e-9aea24ce8f40/latest) is in Pjs. “Unicode Letters Test”: “index.html”: \<!DOCTYPE html\> \<meta charset=utf-8\> \<link rel=stylesheet href=//PyScript.net/latest/pyscript.css\> \<script defer src=//PyScript.net/latest/pyscript.js\>\</script\> \<script defer src=//cdn.JsDelivr.net/npm/p5\>\</script\> \<py-config defer src=pyscript.toml\>\</py-config\> \<py-script defer src=s…

> **[PyScript](https://pyscript.com/@gotoloop/unicode-letters-test/latest?files=global.py)**

> **[Unicode Letters Test](https://gotoloop.pyscriptapps.com/unicode-letters-test/latest/)**

---

<div class="post-metadata">

### Author: ![Fluffy1oo](https://avatars.discourse-cdn.com/v4/letter/f/7ab992/32.png) [@Fluffy1oo](https://discourse.processing.org/u/Fluffy1oo)
#### Post date: [January 13, 2026, 9:16am UTC](https://discourse.processing.org/t/im-trying-to-make-a-game-inspired-by-the-puzzles-of-the-witness/47747/7 "2026-01-13T09:16:20Z")

</div>

I don’t know at all, but I’m using python on a site named basthon

---

<div class="post-metadata">

### Author: ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)
#### Post date: [January 13, 2026, 10:22am UTC](https://discourse.processing.org/t/im-trying-to-make-a-game-inspired-by-the-puzzles-of-the-witness/47747/8 "2026-01-13T10:22:52Z")

</div>

> **[redraw](https://p5js.org/reference/p5/redraw/)**
>
> redraw

> **[mousePressed](https://p5js.org/reference/p5.Element/mousePressed/)**
>
> mousePressed

> [@I'm creating a small game inspired by the puzzles of the witness =](https://discourse.processing.org/t/im-creating-a-small-game-inspired-by-the-puzzles-of-the-witness/47748/1):
>
> ```auto
> cols, rows = LEVELS[current_level]["grid"]
> createCanvas(2*MARGIN + cols*CELL, 2*MARGIN + rows*CELL)
> 
> ```

```auto
    cols, rows = LEVELS[current_level]["grid"]
    createCanvas(2*MARGIN + cols*CELL, 2*MARGIN + rows*CELL).mousePressed(redraw)
    noLoop()

```
