4D Maze Creation! (Norsk)

Jeg har et problem for alle som bryr seg om å prøve.

Du jobber med å ta en 10 x 10 x 10 x 10 tesserakt og designe en labyrint som passer. Labyrinten må være en perfekt labyrint (ingen sløyfer, en sti kan ikke følges og finne starten på stien uten at løseren snur), og må ha minst 25 blindveier og minst 8 forgreninger av andre blindveier.

Svaret du oppgir skal være et bilde, og på det meste av smaken (hvis ikke alle) skal brukes.

note; Moroa er i å skape 4D labyrinten! 2D og til og med 3D er for lett for deg, vil jeg utfordre deg!

Til begrense mulighetene for svar, for at labyrinten din skal aksepteres, må det være kortest mulig labyrint som oppfyller alle kravene som allerede er oppgitt. Med det korteste mener jeg labyrinten med minst fylt tesserakt.

Kommentarer

  • Det ‘ er ikke noe veldig bra spørsmål. 1-Du forklarer ikke ‘ hva en perfekt labyrint er. Visst, jeg kan google det, men jeg burde ikke ‘. 2-Hvordan skal vi svare på spørsmålet? Å tegne en 2D labyrint er enkelt nok. 3D er vanskeligere, men 4D? Høres ikke ‘ ut. Og å bare beskrive labyrinten ville bety at labyrinten måtte være triviell. » Det er en rett vei fra start til slutt, og 10 korte blindveier forgrener seg, og det meste av tesserakten er ubrukt. » Er det et gyldig svar?
  • @Golden I ‘ Jeg jobber med det, kanskje da ‘ ll få bedre respons.
  • +1 fra meg fordi jeg synes det er en god ide om puslespillbygging. Imidlertid vil noen illustrasjoner du har i tankene, eller noen ideer om hvordan et potensielt svarformat kan være, være bra. Ellers forventer jeg i det minste et selvsvar senere …
  • @BmyGuest Jeg ‘ Jeg vil bare overlate til samfunnet hvordan dette skal gjøres . Hvis jeg ikke får ‘, vil jeg ‘ til slutt legge til en dusør.
  • En idé jeg har om dette spørsmålet: kanskje i stedet for å be om individuelle labyrinter som svar, kan du be om teknikker for å designe 4D labyrinter og representere dem på en måte som gjør at ikke-trivielle labyrinter kan presenteres og til og med løses.

Svar

Her er det. Gå til direkte lenke for å se den i full størrelse (eller zoome inn på bildet).

Labyrint

Dette er et plan av brett (vannrett er $ w $ og loddrett er $ z $) hvor hvert brett er et 2D-plan (horisontalt er $ x $ og loddrett er $ y $). For å endre $ x $ og $ y $ posisjon, er det bare å gå rundt i gjeldende tavle.

Pilene lar deg endre $ w $ og $ z $ posisjoner. De får deg til å hoppe ett brett opp (blå), ned (gul), venstre (rød) eller høyre (grønn), i henhold til retning.

Så hvis du er i en bestemt $ (a, b) $ -posisjon for et brett:

  • Ved å bruke pil opp (blå) vil du lande i $ (a, b) $ -posisjonen til brettet rett over den nåværende.
  • Ved å bruke pil ned (gul) vil du lande i $ (a, b) $ -posisjonen til brettet rett under den nåværende.
  • Ved å bruke venstre (rød ) pil, vil du lande i $ (a, b) $ -posisjonen til brettet umiddelbart til venstre for den nåværende.
  • Ved å bruke høyre (grønn) pil, vil du lande i $ (a, b) $ posisjon til styret umiddelbart til høyre for den nåværende.

For å generere dette opprettet jeg dette Java-programmet:

import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import javax.imageio.ImageIO; /** * @author Victor */ public class Tesseracter { public static void main(String[] args) throws IOException { TesseractMaze maze = new TesseractMaze(10, 10, 10, 10); BufferedImage im = maze.draw(); ImageIO.write(im, "png", new File("maze.png")); } public static final class Coordinate4D { private final TesseractMaze maze; private final int w, x, y, z; public Coordinate4D(TesseractMaze maze, int w, int x, int y, int z) { Objects.requireNonNull(maze); if (w < 0 || w >= maze.wSize || x < 0 || x >= maze.xSize || y < 0 || y >= maze.ySize || z < 0 || z >= maze.zSize) throw new IndexOutOfBoundsException(); this.maze = maze; this.w = w; this.x = x; this.y = y; this.z = z; } @Override public int hashCode() { return Objects.hash(maze, w, x, y, z); } @Override public boolean equals(Object another) { if (!(another instanceof Coordinate4D)) return false; Coordinate4D c4d = (Coordinate4D) another; return maze == c4d.maze && w == c4d.w && x == c4d.x && y == c4d.y && z == c4d.z; } public int squareDistance(Coordinate4D another) { Objects.requireNonNull(another); if (maze != another.maze) throw new IllegalArgumentException(); int dw = Math.abs(w - another.w); int dx = Math.abs(x - another.x); int dy = Math.abs(y - another.y); int dz = Math.abs(z - another.z); return dw + dx + dy + dz; } public Coordinate4D minusW() { return w == 0 ? null : new Coordinate4D(maze, w - 1, x, y, z); }; public Coordinate4D plusW() { return w == maze.wSize - 1 ? null : new Coordinate4D(maze, w + 1, x, y, z); }; public Coordinate4D minusX() { return x == 0 ? null : new Coordinate4D(maze, w, x - 1, y, z); }; public Coordinate4D plusX() { return x == maze.xSize - 1 ? null : new Coordinate4D(maze, w, x + 1, y, z); }; public Coordinate4D minusY() { return y == 0 ? null : new Coordinate4D(maze, w, x, y - 1, z); }; public Coordinate4D plusY() { return y == maze.ySize - 1 ? null : new Coordinate4D(maze, w, x, y + 1, z); }; public Coordinate4D minusZ() { return z == 0 ? null : new Coordinate4D(maze, w, x, y, z - 1); }; public Coordinate4D plusZ() { return z == maze.zSize - 1 ? null : new Coordinate4D(maze, w, x, y, z + 1); }; public TesseractMaze getMaze() { return maze; } } public static final class TesseractMaze { private final int wSize, xSize, ySize, zSize; private final Map<Coordinate4D, Node> nodes; private final Node start; public TesseractMaze(int w, int x, int y, int z) { this.wSize = w; this.xSize = x; this.ySize = y; this.zSize = z; nodes = new HashMap<>(w * x * y * z); fill(); this.start = chooseRandomNode(); growMaze(); } private void fill() { for (int a = 0; a < wSize; a++) { for (int b = 0; b < xSize; b++) { for (int c = 0; c < ySize; c++) { for (int d = 0; d < zSize; d++) { Coordinate4D coord = new Coordinate4D(this, a, b, c, d); nodes.put(coord, new Node(coord)); } } } } } public Node nodeAt(Coordinate4D coord) { if (coord == null) return null; return nodes.get(coord); } private Node chooseRandomNode() { int n = (int) (Math.random() * wSize * xSize * ySize * zSize); return new ArrayList<>(nodes.values()).get(n); } private void growMaze() { List<Node> frontier = new ArrayList<>(wSize * xSize * ySize * zSize); frontier.add(start); start.linked = true; while (!frontier.isEmpty()) { Collections.shuffle(frontier); Node n = frontier.get(0); Node next = n.linkRandomUnlinkedNeighbour(); if (next != null) { frontier.add(next); } else { frontier.remove(0); } } } public BufferedImage draw() { int cellWidth = 16; int cellHeight = 16; int boardWidth = cellWidth * (xSize + 1); int boardHeight = cellHeight * (ySize + 1); int arrowSize = 3; int margin = 2; Color red = Color.RED; Color blue = Color.BLUE; Color yellow = new Color(128, 128, 0); Color green = new Color(0, 128, 0); BufferedImage im = new BufferedImage(wSize * boardWidth + cellWidth - 1, zSize * boardHeight + cellHeight - 1, BufferedImage.TYPE_INT_ARGB); Graphics2D g = im.createGraphics(); for (int w = 0; w < wSize; w++) { for (int z = 0; z < zSize; z++) { for (int x = 0; x < xSize; x++) { for (int y = 0; y < ySize; y++) { Coordinate4D c = new Coordinate4D(this, w, x, y, z); Node n = nodeAt(c); int x1 = cellWidth * x + boardWidth * w + cellWidth - 1; int y1 = cellHeight * y + boardHeight * z + cellHeight - 1; int x2 = x1 + cellWidth; int y2 = y1 + cellHeight; int x3 = (x1 + x2) / 2; int y3 = (y1 + y2) / 2; g.setColor(Color.BLACK); if (!n.isLinkedTo(n.minusY())) g.drawLine(x1, y1, x2, y1); if (!n.isLinkedTo(n.plusY())) g.drawLine(x1, y2, x2, y2); if (!n.isLinkedTo(n.minusX())) g.drawLine(x1, y1, x1, y2); if (!n.isLinkedTo(n.plusX())) g.drawLine(x2, y1, x2, y2); if (n.isLinkedTo(n.minusW())) { // Board left, left arrow. g.setColor(red); for (int i = 0; i < arrowSize; i++) { g.drawLine(x1 + margin + i, y3 - i, x1 + margin + i, y3 + i); } } if (n.isLinkedTo(n.plusW())) { // Board right, right arrow. g.setColor(green); for (int i = 0; i < arrowSize; i++) { g.drawLine(x2 - margin - i, y3 - i, x2 - margin - i, y3 + i); } } if (n.isLinkedTo(n.minusZ())) { // Board up, up arrow. g.setColor(blue); for (int i = 0; i < arrowSize; i++) { g.drawLine(x3 - i, y1 + margin + i, x3 + i, y1 + margin + i); } } if (n.isLinkedTo(n.plusZ())) { // Board down, down arrow. g.setColor(yellow); for (int i = 0; i < arrowSize; i++) { g.drawLine(x3 - i, y2 - margin - i, x3 + i, y2 - margin - i); } } } } } } return im; } } public static final class Node { private final Coordinate4D coord; private final List<Node> linkedNeighbours; private List<Node> neighbours; private boolean linked; public Node(Coordinate4D coord) { Objects.requireNonNull(coord); this.coord = coord; linkedNeighbours = new ArrayList<>(8); } public Node linkRandomUnlinkedNeighbour() { List<Node> list = new ArrayList<>(getNeighbours()); list.removeIf(n -> n.linked); if (list.isEmpty()) return null; Collections.shuffle(list); Node next = list.get(0); next.getNeighbours(); linkedNeighbours.add(next); next.linkedNeighbours.add(this); next.linked = true; return next; } @SuppressWarnings("ReturnOfCollectionOrArrayField") public List<Node> getNeighbours() { if (neighbours == null) { List<Node> nodes = new ArrayList<>(Arrays.asList(minusW(), plusW(), minusX(), plusX(), minusY(), plusY(), minusZ(), plusZ())); nodes.removeIf(x -> x == null); neighbours = Collections.unmodifiableList(nodes); } return neighbours; } public boolean isDeadEnd() { return linkedNeighbours.size() == 1; } public boolean isBranch() { return linkedNeighbours.size() > 2; } public boolean isLinkedTo(Node node) { return linkedNeighbours.contains(node); } public TesseractMaze getMaze() { return coord.getMaze(); } public Coordinate4D getCoord() { return coord; } public Node minusW() { return getMaze().nodeAt(coord.minusW()); }; public Node plusW() { return getMaze().nodeAt(coord.plusW()); }; public Node minusX() { return getMaze().nodeAt(coord.minusX()); }; public Node plusX() { return getMaze().nodeAt(coord.plusX()); }; public Node minusY() { return getMaze().nodeAt(coord.minusY()); }; public Node plusY() { return getMaze().nodeAt(coord.plusY()); }; public Node minusZ() { return getMaze().nodeAt(coord.minusZ()); }; public Node plusZ() { return getMaze().nodeAt(coord.plusZ()); }; } } 

Jeg beklager at dette nettstedet ikke har noen syntaksfarging.

Det er hundrevis eller tusenvis av blindveier og forgreningspunkter. Mye mer enn bare 25 og 8 som OP krever.

For hver to lokasjoner er det nøyaktig en vei til hverandre. Det er ingen sykluser i grafen, og den er koblet sammen. Programmet sørger for at (growMaze -metoden).

Det er ikke noe definert start- eller sluttpunkt. Bare få tilfeldig to poeng og prøv å finne en sti. Som du ser, bør det være vanskelig å finne en sti her, siden det er ti tusen posisjoner i denne labyrinten, og det er vanskeligere for menneskelige øyne å se rundt dimensjonene $ w $ og $ z $ for å finne en nyttig sti enn det er i $ x $ og $ y $ dimensjoner.

Du kan bruke programmet til å tilfeldig generere andre labyrinter. Det er også enkelt å endre størrelse: De er de fire tiere i starten av main -metoden. I main -metoden kan du endre til hvilken fil den genererte labyrinten lagres.For å vise det, her er det en mye mindre og enklere $ 4 \ ganger 5 \ ganger 3 \ ganger 2 $ labyrint generert av programmet:

Liten labyrint

Forresten, ved å sette $ w $ til 1 og $ z $ til 1, kan du bruke den til å generere 2D labyrinter. Hvis du bare setter en av dem til 1, vil det være en 3D-labyrint.

Kommentarer

  • Fin, Victor. Du ‘ har slått meg til det i løpet av natten. Jeg skulle skrive et svar i morges – ikke nå skjønt. (@warspyking: Du kan være forbannet for alltid for å holde meg våken klokken 1. )
  • @BmyGuest Var en god programmeringsøvelse. Og det er vanskelig å finne en her. 🙂
  • @BmyGuest Redigert. Er det bedre nå?
  • Hyggelig: D Jeg elsker det, god jobb Victor!
  • Hvor begynner du? : /

Svar

Nå som dette er åpnet igjen vil jeg legge ut » løsning » Jeg hadde for dette i natt før Victor svar. Victor har slått meg til det, og Warspyking har endret seiersforholdene siden , så det er ikke lenger et gyldig svar. Jeg ønsket fortsatt å legge ut dette for å kommentere (og bekrefte / motbevise.)

Svaret fungerer for n-dimensjonale labyrinter, og det er også et algoritme ikke en bestemt labyrint. Jeg legger ikke ut kode her, men algoritmekonseptet.


Min løsning er basert på ideen om at hver piksel / voxel / n-dim-element ( kalles voxel fra nå av ) kan enten være en sti (0) eller en vegg (1). Dette er forskjellig fra det Victor laget, men det kan bli ganske enkelt omgjort til hverandre. ( Bare konverter vegger & åpninger til flere vokser eller omvendt. )

  • Datadimensjonsstørrelsene kalles n,m,k,l…
  • Indeksering starter med 0 for første voxel

Initialiser data:

  • Opprett labyrintdataene som boolsk matrise av nødvendig dimensjonalitet

  • Initialiser alle voxels som 0 (tom)

  • Lag en liste for voxel-indekser av vegger (tom )

  • Sett hver voxel med minst en jevn indeks til 1 (vegg)

  • Lagre wall-voxel-indeksen i listen.

  • Fra nå av, når en vegg blir fjernet:

    • fjern den tilsvarende indeksen fra listen
    • sett den i henhold til Boolean til 0 (tom)

Definer start & sluttposisjon:

Sett i hovedsak de to motsatte » hjørner » start og slutt.

  • Sett voxel for indeks (0,0, …) som startsted
  • Still voxel for index (n, m, …) for å være målmål
  • Hvis mål voxel er en vegg, fjern veggen. (Alle dimensjoner er jevne)

Opprett labyrinten:

Den nåværende labyrinten er et rutenett med isolerte tomme mellomrom.

  • Merk alle tomme mellomrom med en unik etikett.

Gå nå iterat ( WHILE-loop ):

  • Velg en vegg tilfeldig fra indekslisten.
  • Fjern indeksen fra listen ( test aldri en vegg to ganger )

Test : Fjerner denne veggen to tomme mellomrom med forskjellig etikett? NEI: neste iterasjon. ELSE:

  • Fjern vegg

  • Av alle involverte etiketter velger du den med laveste verdi

  • Still alle voxels som har involvert etiketter til denne valgte verdien (= flett tomme mellomrom)

  • neste iterasjon

Stopp iterasjon når ingen indekser er i listen.

Uten korrektur, tror jeg denne algoritmen vil gi deg:

- a non-looping maze from start to end - maximize the size of the maze within the volume - The identical algorithm could be used for arbitrary amount of dimensions 

Opprinnelig hadde jeg tenkt å kode denne algoritmen og så tenke på en fin måte å vise 4D-saken på, men Victor har gjort en god jobb med det allerede, så jeg vil la det være med dette .

Kommentarer

  • Takk for dette muntlige svaret! Det er sikkert nyttig for meg.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *