J
Nothing much to say about today's. I think I wrote basically the same code you'd write in Python, just with fewer characters, more of which are punctuation. I did learn a little bit more about how to use J's step debugger, and that /
is specifically a right fold, so you can use it on a dyad with arguments of different types as long as the list argument is the left one.
data_file_name =: '15.data'
lines =: cutopen fread data_file_name
NB. instructions start with the first line not containing a # character
start_of_moves =: 0 i.~ '#' e."1 > lines
grid =: ,. > start_of_moves {. lines
start_row =: 1 i.~ '@' e."1 grid
start_col =: '@' i.~ start_row { grid
pos =: start_row, start_col
grid =: '.' ( start_of_moves }. lines
translate_move =: monad define"0
if. y = '>' do. 0 1
elseif. y = '^' do. _1 0
elseif. y = '<' do. 0 _1
elseif. y = 'v' do. 1 0
else. 0 0 end.
)
moves =: translate_move move_instructions
NB. pos step move updates grid as needed and returns the new position
step =: dyad define"1 1
new_pos =. x + y
if. '#' = (< new_pos) { grid do. x NB. obstructed by wall
elseif. '.' = (< new_pos) { grid do. new_pos NB. free to move
else. NB. it's 'O', need to push a stack
p =. new_pos NB. pointer to box at end of stack
while. 'O' = (< p) { grid do. p =. p + y end.
if. '#' = (< p) { grid do. x NB. stack is blocked
else. NB. move stack
grid =: 'O.' (< p ,: new_pos)} grid
new_pos
end.
end.
)
score =: dyad define"0 2
+/ ; ((<"0) 100 * i.#y) +&.> (< @: I. @: = & x)"1 y
)
final_pos =: step~/ |. pos , moves NB. / is a right fold
result1 =: 'O' score grid
translate_cell =: monad define"0
if. y = '#' do. '##'
elseif. y = '.' do. '..'
elseif. y = 'O' do. '[]'
else. '@.' end.
)
grid2 =: (,/ @: translate_cell)"1 ,. > start_of_moves {. lines
start_row2 =: 1 i.~ '@' e."1 grid2
start_col2 =: '@' i.~ start_row { grid2
pos =: start_row2, start_col2
grid2 =: '.' (< pos)} grid2 NB. erase the @
NB. (grid; box_pos) try_push dir attempts to push the box at box_pos one
NB. cell in direction dir. box_pos can be either the left or right cell of
NB. the box. it returns (grid; success) where grid is the maybe-changed grid
NB. and success is whether the box moved. if any box that would be pushed
NB. cannot move, this box cannot move either and the grid does not change.
try_push =: dyad define"1 1
'grid pos' =. x
if. ']' = (< pos) { grid do. pos =. pos + 0 _1 end. NB. make pos left cell
source_cells =. pos ,: pos + 0 1
if. 0 = {: y do. NB. moving up or down
target_cells =. (pos + y) ,: (pos + y + 0 1) NB. cells we move into
elseif. y -: 0 _1 do. target_cells =. 1 2 $ pos + y NB. moving left
else. target_cells =. 1 2 $ pos + y + 0 1 end. NB. moving right
NB. Have to check target cells one at a time because pushing a box up or
NB. down may vacate the other target cell, or it may not
trial_grid =. grid
for_tc. target_cells do.
NB. if a target cell is blocked by wall, fail
if. '#' = (< tc) { trial_grid do. grid; 0 return.
elseif. '[]' e.~ (< tc) { trial_grid do.
'trial_grid success' =. (trial_grid; tc) try_push y
if. -. success do. grid; 0 return. end.
end.
end.
NB. at this point either target_cells are clear or we have returned failure,
NB. so push the box
grid =. '[]' (<"1 source_cells +"1 y)} '.' (<"1 source_cells)} trial_grid
grid; 1
)
NB. (grid; pos) step2 move executes the move and returns new (grid; pos)
step2 =: dyad define"1 1
'grid pos' =. x
new_pos =. pos + y
if. '#' = (< new_pos) { grid do. grid; pos NB. obstructed by wall
elseif. '.' = (< new_pos) { grid do. grid; new_pos NB. free to move
else. NB. need to push a box
'new_grid success' =. (grid; new_pos) try_push y
if. success do. new_grid; new_pos else. grid; pos end.
end.
)
'final_grid final_pos' =: > (step2~ &.>)/ (<"1 |. moves) , <(grid2; pos)
result2 =: '[' score final_grid