Thoughts on Puzzle 12 - Arrow Maze?

But if I shift each letter +1 on the row it could eventually move into the right way

1 Like

Look at how all 6 words are organized. Ask yourself which one goes first, second, third etc. Maybe in order of the body.

2 Likes

Nice solutions everyone! Itā€™s nice to learn such things.

1 Like

That is waaay faster than mine. Awesome work!

2 Likes

:smile: Now I realize that the bone hint was too big of a hint. I should have given a hint like itā€™s on the upper part of the body, something like that. But, anyways.

I personally took kind of a bruteforce approach to find the 3rd BODYPART. I had to use an online dictionary to find that word, a dictionary where I can search based on the length of the word, based on what letters it contains, what letters it begins with and what letters it ends with. And manually changing those variables again and again until I found the right one.

1 Like

Hereā€™s my wordy JS solution with backtracking. It can be improved in many ways but as it stands, it takes less than a second to run on my pc. It was fun to revisit backtracking since it is not something I usually need.

const DIRECTION = {
  UP: 'up',
  UP_RIGHT: 'up_right',
  RIGHT: 'right',
  DOWN_RIGHT: 'down_right',
  DOWN: 'down',
  DOWN_LEFT: 'down_left',
  LEFT: 'left',
  UP_LEFT: 'up_left'
}

/**
 * 
 * @param {number | null} value 
 * @param {string} direction 
 * @param {number | null} order 
 */
function Cell(direction, value = null, order = null) {
  this.value = value
  this.direction = direction
  this.order = order
}

Cell.prototype.setCoords = function setCoords(x, y) {
  this.coords = { x, y }
}

/**
 * 
 * @param {Cell[][]} matrix 
 */
function ArrowMaze(matrix) {
  this.matrix = matrix
  this.values = this.matrix.flatMap(row => row.reduce(
    /**
     * 
     * @param {number[]} acc 
     * @param {Cell} cell 
     * @returns 
     */
    (acc, cell) => {
      if (cell.value) acc.push(cell.value)
      return acc
    }, []))
  this.matrix.forEach((row, y) => {
    row.forEach((cell, x) => {
      cell.setCoords(x, y)
    })
  })
}

/**
 * 
 * @param {string} direction 
 * @param {number} x 
 * @param {number} y 
 * @returns {{x: number, y: number}}
 */
ArrowMaze.prototype.getNextCoord = function getNextCoord(direction, x, y) {
  let nextX = x, nextY = y
  if ([DIRECTION.UP, DIRECTION.UP_LEFT, DIRECTION.UP_RIGHT].includes(direction)) nextY--
  if ([DIRECTION.DOWN, DIRECTION.DOWN_LEFT, DIRECTION.DOWN_RIGHT].includes(direction)) nextY++
  if ([DIRECTION.UP_RIGHT, DIRECTION.RIGHT, DIRECTION.DOWN_RIGHT].includes(direction)) nextX++
  if ([DIRECTION.UP_LEFT, DIRECTION.LEFT, DIRECTION.DOWN_LEFT].includes(direction)) nextX--
  return { x: nextX, y: nextY }
}

ArrowMaze.prototype.isValidCoord = function isValidCoord(x, y) {
  return x >= 0 && x < this.matrix[0].length && y >= 0 && y < this.matrix.length
}

/**
 * 
 * @param {Cell} cell 
 * @param {number} value
 */
ArrowMaze.prototype.isValidPlacement = function isValidPlacement(cell, value) {
  return cell.value === value || (cell.value === null && !this.values.includes(value))
}

/**
 * 
 * @param {Cell} cell 
 * @param {number} value 
 */
ArrowMaze.prototype.placeValue = function placeValue(cell, value) {
  cell.value = value
}

/**
 * 
 * @param {Cell} cell 
 */
ArrowMaze.prototype.undoValue = function undoValue(cell) {
  if (!this.values.includes(cell.value)) {
    cell.value = null
  }
}

function resetArrowMaze() {
  return new ArrowMaze([
    [new Cell(DIRECTION.DOWN_RIGHT, 1), new Cell(DIRECTION.DOWN), new Cell(DIRECTION.DOWN), new Cell(DIRECTION.DOWN_RIGHT), new Cell(DIRECTION.LEFT), new Cell(DIRECTION.LEFT), new Cell(DIRECTION.DOWN), new Cell(DIRECTION.DOWN_LEFT)],
    [new Cell(DIRECTION.UP_RIGHT, null, 6), new Cell(DIRECTION.DOWN), new Cell(DIRECTION.RIGHT), new Cell(DIRECTION.DOWN_RIGHT, 17), new Cell(DIRECTION.DOWN, 52), new Cell(DIRECTION.DOWN), new Cell(DIRECTION.DOWN), new Cell(DIRECTION.LEFT, null, 1)],
    [new Cell(DIRECTION.RIGHT), new Cell(DIRECTION.LEFT, 43), new Cell(DIRECTION.UP), new Cell(DIRECTION.DOWN_RIGHT, 14), new Cell(DIRECTION.DOWN_LEFT, null, 5), new Cell(DIRECTION.UP_RIGHT), new Cell(DIRECTION.DOWN, 10), new Cell(DIRECTION.LEFT, 45)],
    [new Cell(DIRECTION.DOWN), new Cell(DIRECTION.RIGHT), new Cell(DIRECTION.UP_RIGHT), new Cell(DIRECTION.UP_LEFT), new Cell(DIRECTION.UP_LEFT, 15), new Cell(DIRECTION.RIGHT, 28), new Cell(DIRECTION.DOWN), new Cell(DIRECTION.LEFT)],
    [new Cell(DIRECTION.RIGHT, 60), new Cell(DIRECTION.LEFT), new Cell(DIRECTION.UP_LEFT, 26), new Cell(DIRECTION.RIGHT), new Cell(DIRECTION.DOWN_RIGHT), new Cell(DIRECTION.LEFT), new Cell(DIRECTION.DOWN), new Cell(DIRECTION.LEFT, 61)],
    [new Cell(DIRECTION.DOWN), new Cell(DIRECTION.RIGHT, null, 2), new Cell(DIRECTION.DOWN), new Cell(DIRECTION.LEFT, 54), new Cell(DIRECTION.DOWN_RIGHT), new Cell(DIRECTION.RIGHT), new Cell(DIRECTION.UP_LEFT, null, 3), new Cell(DIRECTION.DOWN)],
    [new Cell(DIRECTION.UP_RIGHT), new Cell(DIRECTION.DOWN_RIGHT), new Cell(DIRECTION.RIGHT, 56), new Cell(DIRECTION.UP_RIGHT), new Cell(DIRECTION.UP_LEFT), new Cell(DIRECTION.LEFT), new Cell(DIRECTION.UP), new Cell(DIRECTION.UP)],
    [new Cell(DIRECTION.RIGHT), new Cell(DIRECTION.UP_LEFT), new Cell(DIRECTION.UP), new Cell(DIRECTION.LEFT, 33), new Cell(DIRECTION.RIGHT, null, 4), new Cell(DIRECTION.UP), new Cell(DIRECTION.LEFT), new Cell('', 64)],
  ])
}

function solveMaze() {
  const arrow_maze = resetArrowMaze()
  let currValue = 1
  let x = 0, y = 0
  const path = []
  let direction = ''
  do {
    if (arrow_maze.isValidCoord(x, y)) {
      const cell = arrow_maze.matrix[y][x]
      if (arrow_maze.isValidPlacement(cell, currValue)) {
        arrow_maze.placeValue(cell, currValue)
        currValue++
        direction = cell.direction
        path.push(cell)
      }
    } else {
      const last_cell = path.pop()
      const cell = path[path.length - 1]
      direction = cell.direction
      currValue = last_cell.value
      arrow_maze.undoValue(last_cell)
      x = last_cell.coords.x
      y = last_cell.coords.y
    }
    const coords = arrow_maze.getNextCoord(direction, x, y)
    x = coords.x
    y = coords.y
  } while (path.length < 64)
  printCode(arrow_maze)
  return path
}

/**
 * 
 * @param {ArrowMaze} solvedMaze 
 */
function printCode(solvedMaze) {
  const clues = solvedMaze.matrix.flat().filter(cell => cell.order !== null).sort((a, b) => a.order - b.order)
  const baseChar = 'A'.charCodeAt(0) - 1
  let code = ''
  clues.forEach(clue => {
    let charCode = clue.value
    if (clue.value > 52) charCode -= 52
    if (clue.value > 26) charCode -= 26
    code += String.fromCharCode(baseChar + charCode)
  })
  console.log('The answer is: ', code)
}

module.exports = solveMaze

4 Likes

Thanks, I needed the JS code for this.

1 Like

Not clean or elegant but working in 2 seconds.
Inspiration from https://www.baeldung.com/java-solve-maze
For the fun Im planning also to

  1. Solve it with Prolog(but need to relearn)
  2. Encode it to CNF expression and solve it with sat solver
package com.maze.app;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Puzzle 12 Arrow Maze
 */
public class App
{
    private static Cell[] maze;

    private int [] order = new int[64];
    private static int[] must = {1,16,17,52,44,43,14,10,45,27,15,28,60,59,26,63,61,55,54,56,33,64};
    private static int [][] direction =
            {       {9,18,27,45,54},//0
                    {9,17,25,33,41,49,57},
                    {10,18,26,34,50,58},
                    {12,21,30,39},
                    {1,2,3},
                    {1,2,3,4},
                    {14,22,30,38,46,54,62},
                    {14,21,28,35,49,56},
                      {1},//8
                      {17,25,33,41,49,57},
                      {11},
                      {20,38,47},
                      {20,44,52,60},
                      {21,29,37,45,53,61},
                      {22,30,38,46,54,62},
                      {14,13,12,11,10,9,8},
                          {23},//16
                          {16},
                          {10,2},
                          {28},
                          {27,34,41,48},
                          {14,7},
                          {30,38,46,54,62},
                          {18,20,21},
                      {32,40,48,56},//24
                      {29},
                      {19,12,5},
                      {18,9},
                      {10},
                      {30,31},
                      {38,46,54,62},
                      {24,25,26,27,28,29,30},
                       {39},//32
                       {32},
                       {25},
                       {36,38},
                       {63},
                       {36,35,34,33},
                       {46,54,62},
                       {37,35},
                      {48,56},//40
                      {42,43,44,45,46,47},
                      {50},
                      {42},
                      {53,62},
                      {46,47},
                      {37,28,19,10,1},
                      {55,63},
                          {41,34,27,20,13,6},//48
                          {58},
                          {51,52,53,54,55},
                          {44,37,30,23},
                          {43,34,25,16},
                          {48,49,50,51,52},
                          {46,38,30,22,14,6},
                          {47,39,31,23,15,7},
                      {57,58,59,60,61,62},//56
                      {48},
                      {50,34,26,18,10,2},
                      {56,57,58},
                      {61,62},
                      {53,45,37,29,21,13,5},
                      {56,57,58,59,60,61},
                      {},
            } ;


    public static void main( String[] args )
    {
        maze  = new Cell[64];
        initMaze();
        List<Integer> solution = solve(maze);
        System.out.println( solution );
    }

    static void initMaze(){
        for (int i = 0; i < 64; i++) {
            maze[i] =new Cell(-1,direction[i], false);
        }
        maze[0].setOrder(1);
        maze[0].setMust(true);
        maze[11].setOrder(17);
        maze[11].setMust(true);
        maze[12].setOrder(52);
        maze[12].setMust(true);
        maze[17].setOrder(43);
        maze[17].setMust(true);
        maze[19].setOrder(14);
        maze[19].setMust(true);
        maze[22].setOrder(10);
        maze[22].setMust(true);
        maze[23].setOrder(45);
        maze[23].setMust(true);
        maze[28].setOrder(15);
        maze[28].setMust(true);
        maze[29].setOrder(28);
        maze[29].setMust(true);
        maze[32].setOrder(60);
        maze[32].setMust(true);
        maze[34].setOrder(26);
        maze[34].setMust(true);
        maze[39].setOrder(61);
        maze[39].setMust(true);
        maze[43].setOrder(54);
        maze[43].setMust(true);
        maze[50].setOrder(56);
        maze[50].setMust(true);
        maze[59].setOrder(33);
        maze[59].setMust(true);
        maze[63].setOrder(64);
        maze[63].setMust(true);
        maze[16].setOrder(44);
        maze[16].setMust(true);
        maze[25].setOrder(27);
        maze[25].setMust(true);
        maze[33].setOrder(59);
        maze[33].setMust(true);
        maze[42].setOrder(55);
        maze[42].setMust(true);
        maze[36].setOrder(63);
        maze[36].setMust(true);
        maze[10].setOrder(16);
        maze[10].setMust(true);
    }

    public static List<Integer> solve(Cell[] maze) {
        List<Integer> path = new ArrayList<>();
        if (
                explore(
                        maze,
                        0,
                        1,
                        path
                )
        ) {
            return path;
        }
        return Collections.emptyList();
    }

    private static boolean explore(
            Cell[] maze, int index,int order, List<Integer> path) {
        if ((index==63 && order !=64)
                ||(maze[index].isMust() && (order != maze[index].getOrder()))
                || !valid(index,order)
                ||(!maze[index].isMust() && maze[index].getOrder() != -1 && (order != maze[index].getOrder()))){
            return false;
        }

        path.add(index);
        System.out.println("index:" +index + "added to path, order:"+ order);
        if (!maze[index].isMust()) {
            maze[index].setOrder(order);//setVisited
        }
        if (index ==63 || order == 64) {
            return true;
        }

        for (int i =0; i<maze[index].getDirection().length;i++ ) {
            if (
                    explore(
                            maze,
                            maze[index].getDirection()[i],
                            order+1,
                            path
                    )
            ) {
                return true;
            }
        }

        path.remove(path.size() - 1);
        if (!maze[index].isMust()){
            maze[index].setOrder(-1);
        }
        System.out.println(index +" index:"+ maze[path.size() - 1].getOrder() + "order removed");
        return false;
    }

    private static boolean valid(int index, int order) {
        return (!orderInMustlist(order) ||
                (index==0 && order==1)
                ||(index==10 && order==16)
                ||(index==11 && order==17)
                ||(index==12 && order==52)
                ||(index==16 && order==44)
                ||(index==17 && order==43)
                ||(index==19 && order==14)
                ||(index==22 && order==10)
                ||(index==23 && order==45)
                ||(index==25 && order==27)
                ||(index==28 && order==15)
                ||(index==29 && order==28)
                ||(index==32 && order==60)
                ||(index==33 && order==59)
                ||(index==34 && order==26)
                ||(index==36 && order==63)
                ||(index==39 && order==61)
                ||(index==42 && order==55)
                ||(index==43 && order==54)
                ||(index==50 && order==56)
                ||(index==59 && order==33)
                ||(index==63 && order==64));
    }

    private static boolean orderInMustlist(int order) {
        for (int i = 0; i < must.length; i++) {
            if (must[i]==order){
                return true;
            }
        }
        return false;
    }

    public static class Cell {

        private int order;
        private int[] direction;
        private boolean must;

        public int getOrder() {
            return order;
        }
        public void setOrder(int order) { this.order = order;}

        public int[] getDirection() {
            return direction;
        }

        public void setMust(boolean must) {
            this.must = must;
        }
        public boolean isMust() {
            return must;
        }

        public Cell(int order,int[] direction,boolean must){
            this.order = order;
            this.direction = direction;
            this.must = must;
        }
    }

}

2 Likes

Hey guys,

I solved the puzzle with no code or guessing, I just used logic. Now, I got two questions:

  • how can I check my solution?
  • am I allowed to share my approach/ solution here? I mean the challenge is already expired.

Thank you

2 Likes

Iā€™d love to know what logic you used to do solve it without coding. I tried to solve the Arrow Maze manually but never cracked the correct approach. I just know that going backward starting from 64 is the best approach but when the gaps of unknown numbers between two known numbers were large, there I couldnā€™t make much progress.

3 Likes

yeah I did that backwards approach but i started it too late. I have got into the flow of making time for these puzzles around my life tho now haha

2 Likes

I think you posted too late as the puzzle ended a while ago. You can enter the solution here but the deadline long passed so guess you wont be able to know if you where right

2 Likes

I couldnā€™t solve it but got to know the 6 letter answer to the puzzle from someone else through a private message here.

1 Like

I actually did it without coding and I jumped around a lot with the numbers doing the ones that I knew were 100% correct because no other number can fit there. I then placed colored dots(on Photoshop) on all possible outcomes with the ones that were left and eventually, a pattern started to appear. With the colored dots I was able to cross out dead ends until only 1 path was left.

2 Likes

that sounds cool, looking at the examples I understand how they did it but my python skills are lacking so I did not come up with a code solution

1 Like

I treated it like a cryptic sudoku lol

1 Like

What an incredible and complicated puzzle. A couple of days ago I entered the competition and I love trying to solve the puzzles that have already expired even if they donā€™t help me win. Thank for doing this amazing puzzles!!!

2 Likes

How do i get to the arrow puzzle?
@param

How do I get to these puzzle are is it to late?

You can see all puzzles from the past here https://community.rapyd.net/c/hack-the-galaxy/challenges-archived/42

1 Like