Created
December 27, 2025 11:46
-
-
Save joostrijneveld/4f8c3c5052e8a367e4f400ec69eaf25a to your computer and use it in GitHub Desktop.
Solver script for Blue Prince Mora Jai boxes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from collections import deque | |
| import sys | |
| from statistics import multimode | |
| # een mora jai box is een combinatie van 4 hoekjes-targets en 9 velden | |
| ORANJE = 0 | |
| ZWART = 1 | |
| GROEN = 2 | |
| PAARS = 3 | |
| GEEL = 4 | |
| ROOD = 5 | |
| GRIJS = 6 | |
| WIT = 7 | |
| ROZE = 8 | |
| BLAUW = 9 | |
| cmaps = [ | |
| "ORANJE", | |
| "ZWART ", | |
| "GROEN ", | |
| "PAARS ", | |
| "GEEL ", | |
| "ROOD ", | |
| "GRIJS ", | |
| "WIT ", | |
| "ROZE ", | |
| "BLAUW ", | |
| ] | |
| TOPLEFT = 9 | |
| TOPRIGHT = 10 | |
| BOTLEFT = 11 | |
| BOTRIGHT = 12 | |
| # dus een lijst van 13 van deze units | |
| # eerst 4 targets en dan 9 boxjes | |
| # in een map houden we per node bij vanaf welke andere node we er kwamen, en met welke box | |
| path = {} | |
| visited = set() | |
| def is_solution(box): | |
| return ( | |
| box[TOPLEFT] == box[0] | |
| and box[TOPRIGHT] == box[2] | |
| and box[BOTLEFT] == box[6] | |
| and box[BOTRIGHT] == box[8] | |
| ) | |
| def render_box(box): | |
| for row in [[0, 1, 2], [3, 4, 5], [6, 7, 8]]: | |
| for i in row: | |
| print(cmaps[box[i]], end=" ") | |
| print() | |
| def render_path(previous, previous_click, box): | |
| boxes = [] | |
| sequence = [] | |
| i = 0 | |
| while box in previous: | |
| if previous[box] == "START": | |
| break | |
| boxes.append(previous[box]) | |
| sequence.append(previous_click[box]) | |
| box = previous[box] | |
| i += 1 | |
| for i, (box, n) in enumerate(reversed(list(zip(boxes, sequence)))): | |
| print("#", i) | |
| render_box(box) | |
| print("click", n + 1, cmaps[box[n]]) | |
| print("") | |
| for i, (box, n) in enumerate(reversed(list(zip(boxes, sequence)))): | |
| print("click", n + 1, cmaps[box[n]]) | |
| def swap(box, a, b): | |
| box[a], box[b] = box[b], box[a] | |
| def get_neighbours(field): | |
| neighbours = [] | |
| y = field // 3 | |
| x = field % 3 | |
| if y > 0: | |
| neighbours.append((y - 1) * 3 + x) | |
| if y < 2: | |
| neighbours.append((y + 1) * 3 + x) | |
| if x > 0: | |
| neighbours.append(y * 3 + (x - 1)) | |
| if x < 2: | |
| neighbours.append(y * 3 + (x + 1)) | |
| return neighbours | |
| def process_color(box, field, color=None): | |
| # voor blauw willen we de kleur kunnen meegeven | |
| if color == None: | |
| color = box[field] | |
| if color == BLAUW: | |
| if box[4] == BLAUW: | |
| return box | |
| return process_color(box, field, color=box[4]) | |
| newbox = list(box) | |
| y = field // 3 | |
| x = field % 3 | |
| if color == ORANJE: | |
| multimodes = multimode([box[f] for f in get_neighbours(field)]) | |
| # als er precies eentje de meeste stemmen heeft wordt het die | |
| if len(multimodes) == 1: | |
| newbox[field] = multimodes[0] | |
| elif color == ZWART: | |
| newbox[y * 3 + 1] = box[y * 3 + 0] | |
| newbox[y * 3 + 2] = box[y * 3 + 1] | |
| newbox[y * 3 + 0] = box[y * 3 + 2] | |
| elif color == GROEN: | |
| swaptargets = [8, 7, 6, 5, 4, 3, 2, 1, 0] | |
| swap(newbox, field, swaptargets[field]) | |
| elif color == PAARS: | |
| if y < 2: # onderste rij doet paars niks | |
| swap(newbox, y * 3 + x, (y + 1) * 3 + x) | |
| elif color == GEEL: | |
| if y > 0: # bovenste rij doet geel niks | |
| swap(newbox, y * 3 + x, (y - 1) * 3 + x) | |
| elif color == ROOD: | |
| for i in range(9): | |
| if box[i] == ZWART: | |
| newbox[i] = ROOD | |
| if box[i] == WIT: | |
| newbox[i] = ZWART | |
| elif color == GRIJS: | |
| pass | |
| elif color == WIT: | |
| newbox[field] = GRIJS | |
| for f in get_neighbours(field): | |
| if newbox[f] == WIT: | |
| newbox[f] = GRIJS | |
| elif newbox[f] == GRIJS: | |
| newbox[f] = box[field] | |
| elif color == ROZE: | |
| # 0 1 2 | |
| # 3 4 5 | |
| # 6 7 8 | |
| if field == 0: | |
| seq = [1, 4, 3] | |
| if field == 1: | |
| seq = [0, 2, 5, 4, 3] | |
| if field == 2: | |
| seq = [1, 5, 4] | |
| if field == 3: | |
| seq = [0, 1, 4, 7, 6] | |
| if field == 4: | |
| seq = [0, 1, 2, 5, 8, 7, 6, 3] | |
| if field == 5: | |
| seq = [1, 2, 8, 7, 4] | |
| if field == 6: | |
| seq = [3, 4, 7] | |
| if field == 7: | |
| seq = [3, 4, 5, 8, 6] | |
| if field == 8: | |
| seq = [4, 5, 7] | |
| oldseq = seq[-1:] + seq[0:-1] | |
| for a, b in zip(seq, oldseq): | |
| newbox[a] = box[b] | |
| return tuple(newbox) | |
| def bfs(start): | |
| box = tuple(start) | |
| queue = deque([box]) | |
| visited = set({}) | |
| previous = {box: "START"} | |
| previous_click = {} | |
| while queue: | |
| box = queue.popleft() | |
| if box in visited: | |
| continue | |
| visited.add(box) | |
| if is_solution(box): | |
| print("Found solution") | |
| render_path(previous, previous_click, box) | |
| sys.exit(0) | |
| for i in range(9): | |
| newbox = process_color(box, i) | |
| if newbox != box: | |
| if newbox not in previous: | |
| previous[newbox] = box | |
| previous_click[newbox] = i | |
| queue.append(newbox) | |
| def flatten_box(box): | |
| return [x for row in box for x in row] | |
| VESTIBULE = [ | |
| GRIJS, | |
| GROEN, | |
| GRIJS, | |
| ORANJE, | |
| ZWART, | |
| ROOD, | |
| ZWART, | |
| WIT, | |
| PAARS, | |
| ZWART, | |
| PAARS, | |
| ORANJE, | |
| ROOD, | |
| ] | |
| TROPHYROOM = [ | |
| WIT, | |
| ROOD, | |
| GRIJS, | |
| GRIJS, | |
| ROZE, | |
| GRIJS, | |
| ZWART, | |
| ROOD, | |
| WIT, | |
| WIT, | |
| WIT, | |
| WIT, | |
| WIT, | |
| ] | |
| PUMPROOM = [ | |
| PAARS, | |
| BLAUW, | |
| PAARS, | |
| ZWART, | |
| GROEN, | |
| ORANJE, | |
| ZWART, | |
| GROEN, | |
| ORANJE, | |
| PAARS, | |
| PAARS, | |
| PAARS, | |
| PAARS, | |
| ] | |
| BILLIARD = [ | |
| ROZE, | |
| WIT, | |
| ROZE, | |
| BLAUW, | |
| GRIJS, | |
| BLAUW, | |
| ROZE, | |
| ROOD, | |
| ROZE, | |
| ROOD, | |
| ROOD, | |
| ROOD, | |
| ROOD, | |
| ] | |
| FOYER = [ | |
| GROEN, | |
| GROEN, | |
| GROEN, | |
| GRIJS, | |
| ORANJE, | |
| ORANJE, | |
| BLAUW, | |
| GRIJS, | |
| PAARS, | |
| GROEN, | |
| GROEN, | |
| GROEN, | |
| GROEN, | |
| ] | |
| box = BILLIARD | |
| assert len(box) == 13 | |
| bfs(box) | |
| # flatbox = flatten_box(box) | |
| # bfs(flatbox) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment