-1

I have been given this assignment for school:

You have been given a puzzle consisting of a row of squares each containing an integer, like this:

6, 4, 1, 3, 3, 1, 4, 1, 1, 0

The bold number on the initial square is a marker that can move to other squares along the row. At each step in the puzzle, you may move the marker the number of squares indicated by the integer in the square it currently occupies. The marker may move either left or right along the row but may not move past either end. The goal of the puzzle is to move the marker to the 0 at the far end of the row.

The program checks the index you are currently on, and moves either left or right a number of squares based on the integer at that index in the array. It decides this based on the bounds of the array, if it can't move the required number of squares to the left it will move to the right, and vice versa. In this program, the first move has to be 6 to the right, since it cannot move 6 spaces left without going out of bounds. Then, it has to move 4 left since it cant move 4 right, and it goes on like that.

I have got this working, and printing the process is worth extra credit. I have it printing the process, but it is out of order.

here is my code:

def self.solvable(start, board)

     return false if start>= board.length || start<0
     return false if @@infinite[start] == -1
     return true if board[start] == 0

     @@infinite[start] = -1

     if solvable(board[start] + start, board)
          puts "Shifted right " + board[start].to_s + " spaces, from index " + start.to_s + " to index " + (board[start] + start).to_s
          return true
     else
          puts "Shifted left " + board[start].to_s + " spaces, from index " + start.to_s + " to index " + (start - board[start]).to_s
     end       
     return solvable(start - board[start], board)
end

print "Enter an array of numbers: "
input = gets.chomp!

board = input.each_char.map(&:to_i)
@@infinite = input.each_char.map(&:to_i)
puts solvable(0, board)

I do not understand how to make the code output in a more logical order, printing 6 spaces right, 4 spaces left, etc... instead of the current output, which is:

Shifted left 4 spaces, from index 6 to index 2

Shifted left 3 spaces, from index 3 to index 0

Shifted left 1 spaces, from index 2 to index 1

Shifted left 1 spaces, from index 5 to index 4

Shifted right 1 spaces, from index 8 to index 9

Shifted right 1 spaces, from index 7 to index 8

Shifted right 3 spaces, from index 4 to index 7

Shifted right 4 spaces, from index 1 to index 5

Shifted right 6 spaces, from index 0 to index 6

JosephKidd
  • 23
  • 3
  • Not completely clear. How decide which side to move? Also, it is not possible to run your code, please update and make it working by pasting it. This will increase the probability somebody helps. – iGian Apr 05 '20 at 16:56
  • I very much doubt that your assignment was the sequence of numbers `6, 4, 1, 3, 3, 1, 4, 1, 1, 0` and nothing else, not even a question. You must begin by stating your question, rather than hoping the reader can figure it out by studying your code, which is a poor use of the reader's time and probably won't work anyway given that your code is faulty. The best thing to do is edit your question and cut and paste to the beginning of your answer the actual question you have been given, verbatim. – Cary Swoveland Apr 05 '20 at 19:35
  • @CarySwoveland I assume the program should check if you can reach `0` by (repeatedly) moving `n` elements to the left or to the right with `n` being the value of the element you're on. In the beginning you can move +6 or -6. The next possible movements in the positive direction would be +4 or -4. In the negative direction it would be +3 and -3. There are two ways at each step, hence the recursion. Some paths may be infinite loop (e.g. +6, +4, +6, +4, ...) whereas others may lead to `0` (e.g. -6, +3, +1, +1) – Stefan Apr 06 '20 at 06:22
  • 1
    @Stefan, as I understand, you are suggesting that if `arr` is the given array, after moves +6, +4, taking you to index 10, the value at index 10 is `arr[10 % 10] #=> arr[0] => 6`? and that the value at index -6 is `arr[-6 % 10] #=> arr[4] => 3`. Correct? That explains the mysterious 0 at the end, which evidently can be regarded as an absorbing state. – Cary Swoveland Apr 06 '20 at 18:25
  • 1
    @Stefan, I was thrown off by the fact that there is a 4 at index 1 as well as index 6, but the main reason was that, being eager to get on with a solution, I did not read the question carefully enough. I make no apology for that, however, as that behavior, consistently applied, has resulted in me being able to work on many interesting problems in the past, problems that generally were more interesting than the actual ones. Moreover, no harm has been done as you are always there to set me straight, causing me to revise my original answer. – Cary Swoveland Apr 06 '20 at 18:30
  • 1
    Why ask a question if you are not going to return to view the answers? – Cary Swoveland Apr 07 '20 at 05:28
  • The initial `return true if board[start] == 0` also implies that the goal is reaching (a) `0`, not necessarily the last element. – Stefan Apr 07 '20 at 06:03
  • @Stefan, I too understood the goal was to get back to position zero, but I don't what you mean by "the last element". – Cary Swoveland Apr 07 '20 at 18:06
  • @CarySwoveland _position_ zero? I thought the goal was to reach an element with a _value_ of zero. That would be the very last element in the example. – Stefan Apr 07 '20 at 18:33
  • Joseph, @iGain and I both asked for clarification some time ago. You saw our comments but chose to disregard them. You have also seen from the discussion between me and... – Cary Swoveland Apr 07 '20 at 18:36
  • ...@Stefan that there is uncertainty about what the problem is. Still, you may done nothing to clarify the question. That is irresponsible behavior at SO. – Cary Swoveland Apr 07 '20 at 18:42

1 Answers1

1

Assumption

I assume the game begins at position 0. Each move increases or decreases the position by an integal amount. The objective is to get back to position 0 after the first move has been made.

We are given an array, arr, of integers and a mapping from positions to indices of the array. For position p the index of arr is given by p % arr.size.

If we are at position p we obtain the value may move to position p + n or p - n, where

n = arr[p % arr.size]

For the example given:

arr = [6, 4, 1, 3, 3, 1, 4, 1, 1, 0]

(arr.size #=> 10) and p initially zero,

n = arr[0 % 10]
  #=> arr[0] => 6

so we may move to position +6 or -6. If we move to +6, we calculate

n = arr[6 % 10]
  #=> 4

so we may move to position 6+4 #=> 10 or 6-4 #=> 2. If we move to -6, we calculate

n = arr[-6 % 10]
  #=> 3

so we may move to position -6-3 #=> -9 or -6+3 #=> -3.

Note that arr[9] #=> 0 can be regarding as an absorbing state.

Code

The method I've chosen to use is recursive.

def onward_to_zero(arr, pos=0)
  n = arr[pos % arr.size]
  return [] if n.zero?
  return [-n] if (pos-n).zero?
  return [n] if (pos+n).zero?
  if rand < 0.5
    rv = onward_to_zero(arr, pos-n)
    return [-n] + rv unless rv.empty?
    rv = onward_to_zero(arr, pos+n)
    return [n] + rv unless rv.empty?
  else
    rv = onward_to_zero(arr, pos+n)
    return [n] + rv unless rv.empty?
    rv = onward_to_zero(arr, pos-n)
    return [-n] + rv unless rv.empty?
  end
  []
end

I believe it can be proven that there is always a path back to zero, but I have not given thought to a proof.

Examples

arr = [6, 4, 1, 3, 3, 1, 4, 1, 1, 0]

onward_to_zero(arr)
  #=>       [-6, 3, 1, -1, 1, -1, -1, 4]
  # pos % 10  0  4  7   8  7   8   7  6    
  # pos->  0 -6 -3 -2  -3 -2  -3  -4  0

arr = [3, 2, 4, 1, 3, 6, 2]

onward_to_zero(arr)
  #=>    [3, -1, 4, 2, 2, 1, -3, 2, -1, -4, -6, -2, 3]
  # pos-> 3   2  6  8 10 11   8 10   9   5   -1 -3  0

arr = [3, 3]

onward_to_zero(arr)
  #=>    [-3, 3]
  # pos-> -3  0

arr = [7, 26, 33, 18, 7, 13]
onward_to_zero(arr)
  #=>     [-7, -13,  7, 13]
  # pos->  -7  -20 -13   0

Discussion

Notice that if rand < 0.5 causes me to consider a reduction in the position before an increase in the position roughly half the time. If I were always to consider a reduction before an increase, or vice-versa, I could easily get a stack level too deep error.

Even with that probability mechanism, however, the method gives quite varied results and could still result in a stack level too deep error. Here are the results I obtained by running the first example 10 times.

[6, -4, 1, -3] 
[-6, 3, 1, -1, -1, 4] 
[6, 4, 6, 4, 6, 4, 6, 4, 6,..., -1, -1, 4] (824 elements) 
[6, 4, -6, -3, 4, 1, -4, -1,..., -4, 1, -3] (386 elements) 
[-6, 3, 1, -1, -1, 4] 
[-6, -3, 4, 1, 4] 
[-6, 3, 1, -1, 1, -1, -1, 4] 
[-6, -3, -4, -1, -4, 1, -3, 6, 4, 6, 4] 
[-6, -3, -4, 1, -1, -1, -4, -1, 4, 1, 4, 6, 4]
[-6, 3, -1, 4]
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100