A Tiny Explorer

MATL, 68 59 58 bytes

'?'7XJQtX"'s'jh5e"@2#1)t35>)-1l8t_4$h9M)b'nsew'=8M*sJ+XJ+(

Try it online!

Explanation

The map is kept in the bottom of the stack and gradually filled. The current position of the explorer is stored in clipboard J.

The map uses matrix coordinates, so (1,1) is upper left. In addition, column-major linear indexing is used. This means that the elements of the 8×8 matrix representing the map are accessed with a single index as follows:

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

So for example the element (3,2) of the matrix is the element with linear index 11. Movement towards North, South, East and West respectively corresponds to adding -1, 1, 8 or -8 to the linear index. The array [-1 1 8 -8] serves to encode two different things:

  • The possible displacements of the explorer.
  • The relative positions of features detected with the spyglass. These positions are relative to the current position of the explorer.

The input string is arranged into chunks of 5 characters. Since the first chunk is missing the first character (that which indicates movement), an initial s is arbitrarily included to make all chunks the same size. To compensate for this, the explorer starts at position 7, not 8, so the initial displacement to the South (add 1 to the linear index) leaves them at position 8.

The chunks of 5 characters are processed in a loop. The first character updates the position, and the remaining 4, if different than #, are written into the adequate entries of the matrix that represents the map.

'?'          % push '?'. The map will initially be filled with this
7XJ          % push 7: initial position of the explorer. Copy into clipboard J
Qt           % add 1. Duplicate
X"           % 8x8 matrix containing '?'
'n'jh        % take input string. Prepend 'n'
5e           % reshape into a 5-column matrix
"            % for each column (chunk)
  @          %   push current chunk
  2#1)       %   split chunk into its first char and an array with the other 4
  t35>       %   duplicate. Logical index of chars different than #
  )          %   apply that index to keep characters different than #
  -1l8t_4$h  %   array [-1 1 8 -8]
  9M         %   push logical index again
  )          %   apply that index to keep only relevant relative positions
  b          %   bubble up in stack: move first char of chunk to top
  'nsew'=    %   logical index that tells if that char is 'n', 's', 'e' or 'w'
  8M         %   push array [-1 1 8 -8] again
  *          %   multiply element-wise. Only one of the four results will be nonzero
  s          %   sum of the array. Gives displacement of the explorer
  J+         %   push position of the explorer and add to compute new position
  XJ         %   update position in clipboard J
  +          %   add updated position of explorer to relative positions of features
  (          %   write those fearttures into the indexed entries of the map
             % end for each. Implicitly display

C, 210 208 207 bytes

This one uses printf and scanf to read input, and a linearized array instead of x,y; so I feel it is sufficiently different from millibyte's.

Golfed:

 main(p){char*i,*j,m[80];for(p=73,i=m+p;p--;m[p]=63);for(p=8;scanf("%5s",i)>0;p+=*j=='n'?8:*j=='s'?-8:*j=='e'?1:-1)for(j=i;j-i<4;j++)if(*j^35)m[p+"qajh"[j-i]-'i']=*j;for(p=72;m[p]=0,p-=8;)printf("%s\n",m+p);}

Somewhat-ungolfed:

main(p){
    char*i,*j,m[80];
    for(p=73,i=m+p;p--;m[p]=63);                   // fill with ?
    for(p=8;scanf("%5s",i)>0;
            p+=*j=='n'?8:*j=='s'?-8:*j=='e'?1:-1)  // read 5-at-a-time
        for(j=i;j-i<4;j++)
            if(*j^35)m[p+"qajh"[j-i]-'i']=*j;      // update map positions
    for(p=72;m[p]=0,p-=8;)printf("%s\n",m+p);      // output line-by-line
}

Representation:

  // board: (vertically reversed when printed)
    0  1  2  3  4  5  6  7
    8  9  10 ...
    16 18 19 ...
    ...
    56 57 58 59 60 61 62 63
  
  // offsets and offset order, or why "qajh": 
    s2      -8       a
  w4  e3  -1 0+1   h i j
    n1      +8       q   <- offset by +'i'

Also, you start at position 8 because this shaves a char or so off the print-loop.


Ruby, 169 147 bytes

Full program. Takes in the input string from STDIN (you probably need to pipe it in from a file to prevent any trailing newlines from messing things up) and outputs the resultant map to STDOUT.

Trimmed a ton by putting all the strings into one and then splitting them later.

m=??*64
d=0
x=56
gets.each_char{|c|d<4?(w=x+(d>2?-1:d>1?1:d<1?-8:d<2?8:0)
m[w]=c if c>?$):x+=c>?v?-1:c<?f?1:c>?q?8:-8
d+=1;d%=5}
puts m.scan /.{8}/

Ungolfed:

m = ?? * 64                 # 64 "?" symbols
                            # y axis counts downwards; 0-7 is top row
d = 0                       # Keep track of which direction we're looking
x = 56                      # Position, bottom left corner (0,7)
gets.each_char do |c|       # For each character from first line of STDIN
    if d < 4                # Looking in a direction
        if    d > 2         # d == 3; looking west
            w = x - 1
        elsif d > 1         # d == 2; looking east
            w = x + 1
        elsif d < 1         # d == 0; looking north
            w = x - 8
        else                # d == 1; looking south
            w = x + 8
        end
        m[w] = c if c > ?$  # Only '#' gets rejected by this step
    else                    # Moving in a direction
        if    c > ?v        # c == 'w'
            x -= 1
        elsif c < ?f        # c == 'e'
            x += 1
        elsif c > ?q        # c == 's'
            x += 8
        else                # c == 'n'
            x -= 8
        end
    end
    d = (d + 1) % 5         # Look in the next direction
end
puts m.scan /.{8}/          # Split map into rows of 8