function action = CS4300_agent(percept)
% CS4300_random_agent - random action agent
% On input:
%     percept (1x5 Boolean vector): percept values
%      (1): Stench
%      (2): Breeze
%      (3): Glitters
%      (4): Bumped
%      (5): Screamed
% On output:
%     action (int): action selected by agent
%       FORWARD = 1;
%       ROTATE_RIGHT = 2;
%       ROTATE_LEFT = 3;
%       GRAB = 4;
%       SHOOT = 5;
%       CLIMB = 6;
% Call:
%     a = CS4300_random_agent([0,0,0,0,0]);
% Author:
%     N Wernecke
%     UU
%     Fall 2017/Spring 2022
%
%
%     board (4x4): exploration
%      (0): safe
%      (1): Potential Pit/Wumpus
%      (-1): unexplored

persistent board pit_board wumpus_board x y dir action_taken... 
action_queue escape arrow steps wumpus_killed last_position,

%setup
if isempty(board)
    board = -ones(4,4);
    pit_board = zeros(4,4);
    wumpus_board = zeros(4,4);
    board(4,1) = 0;
    x = 1;
    y = 1;
    dir = 0;
    action_taken = 0;
    escape = [];
    arrow = 1;
    steps = 0;
    wumpus_killed = 0;
    last_position = [0,0];
end

[x,y,dir] = CS4300_act(x,y,dir,action_taken);

GRAB = 4;
CLIMB = 6;

% Action queue are steps to shoot an arrow or move to a neighbor
if ~isempty(action_queue)
    
    if action_queue(1) == 9 %arrow was shot
        action_queue = [];
        
        %wumpus killed, reset boards to unexplored
        if percept(5)==1 
            wumpus_killed = 1;
            wumpus_board = -ones(4,4);
            board = -ones(4,4);
            pit_board = zeros(4,4);
            board(4-y+1,x) = 0;

        %no wumpus in front of agent so move forward (does not check for pit)
        else        
            action = 1;
            last_position = [x,y];
            action_taken = action;
            return
        end
    
    else
        action = action_queue(1);
        action_queue = action_queue(2:end);
        action_taken = action;
        return
    end
end

if ~isempty(escape)   % pre-planned escape sequence of actions
    action = escape(1);
    escape = escape(2:end);
    action_taken = action;
    return
end

if percept(3)==1  % Glitter percept
    [sol,nodes] = CS4300_Wumpus_A_star(board,[x,y,dir],[1,1,0],...
        'CS4300_A_star_Man');
    sol = [x,y,dir,GRAB;sol(2:end,:);1,1,1,CLIMB];
    escape = sol(:,end);
    action = escape(1);
    escape = escape(2:end);
    action_taken = action;
    return
end


%update board that current location is safe
board(4-y+1,x) = 0;
wumpus_board(4-y+1,x) = -1;
pit_board(4-y+1,x) = -1;

steps = steps + 1;

neighbors = BR_Wumpus_neighbors(x,y);
[numNeighbors, numCols] = size(neighbors);

if percept(2)==1 % Breeze percept

   %anywhere not yet visited is potential pit
   potential_pit = [];
   for i = 1:numNeighbors
      if pit_board(4 - neighbors(i,2) + 1, neighbors(i)) ~= -1
          potential_pit = [potential_pit; neighbors(i,:)];
      end
   end
   
   p = size(potential_pit); 
   val = 1/p(1);

   for i = 1:p
       pit_x = 4 - potential_pit(i,2) + 1;
       pit_y = potential_pit(i);
       pit_board(pit_x, pit_y) = val + pit_board(pit_x, pit_y);
       board(pit_x, pit_y) = 1;
   end

else %no stench, mark neighbors safe
   for i = 1:numNeighbors;
      pit_board(4 - neighbors(i,2) + 1, neighbors(i)) = -1;
   end
end


if percept(1)==1 % Stench percept (processed very similarly as breeze)
   
    potential_wumpus = [];
   for i = 1:numNeighbors
      if wumpus_board(4 - neighbors(i,2) + 1, neighbors(i)) ~= -1
          potential_wumpus = [potential_wumpus; neighbors(i,:)];
      end
   end

   [p, cols] = size(potential_wumpus);
   val = 1/p(1);

  for i = 1:p
      w_x = 4 - potential_wumpus(i,2) + 1;
      w_y = potential_wumpus(i);
    wumpus_board(w_x, w_y) = val + wumpus_board(w_x, w_y);
    board(w_x, w_y) = 1;
  end

  for i = 1:p % check if arrow worth shooting

       %if wumpus prob >=1, shoot
       if wumpus_board(4 - potential_wumpus(i,2) + 1, potential_wumpus(i)) >= 1 && arrow == 1 
           arrow = 0;
           action_queue = move_to(potential_wumpus(i)-x, potential_wumpus(i,2)-y, dir);
           action_queue(action_queue==1)=5;
           action_queue(end + 1) = 9;
           action = action_queue(1);
           action_taken = action;
           last_position = [x, y];
           action_queue = action_queue(2:end);
           return

       %shoot if two or fewer neighbors
       elseif numNeighbors < 3 && arrow == 1 
           arrow = 0;
         
           action_queue = move_to(potential_wumpus(2)-x, potential_wumpus(2,2)-y, dir);
           action_queue(action_queue==1)=5;
           action_queue(end + 1) = 9;
           action = action_queue(1);
           last_position = [x, y];
           action_taken = action;
           action_queue = action_queue(2:end);
           return
       end
  end

else %no stench
   for i = 1:numNeighbors
      wumpus_board(4 - neighbors(i,2) + 1, neighbors(i)) = -1;
   end
end



%explore safe unexplored
for i = 1:numNeighbors
    safe_x = 4 - neighbors(i,2) + 1;
    safe_y = neighbors(i);
    if board(safe_x, safe_y) == -1 ...
            && pit_board(safe_x, safe_y) == -1 ...
            && wumpus_board(safe_x, safe_y) == -1
        action_queue = move_to(neighbors(i)-x, neighbors(i,2)-y, dir);
        last_position = [x, y];
        action = action_queue(1);
        action_taken = action;
        action_queue = action_queue(2:end);
        return
    end
end


%find count neighbors explored safely, and those dangerous
explored = 0;
probable_death = 0;
for i = 1:numNeighbors
    if board(4 - neighbors(i,2) + 1, neighbors(i)) == 0
        explored = explored + 1;
    end
    if board(4 - neighbors(i,2) + 1, neighbors(i)) == 1
        probable_death = probable_death + 1;
    end
end


%if steps > 50 agent becomes more risky. Move to 
% least dangerous neighbor
if steps > 50 && probable_death > 1
   
    probs = [2; 2; 2; 2];
    for i = 1:numNeighbors
        if board(4 - neighbors(i,2) + 1, neighbors(i)) == 1
            probs(i) = wumpus_board(4 - neighbors(i,2) + 1, neighbors(i)) + pit_board(4 - neighbors(i,2) + 1, neighbors(i));
        end
    end

    [M,I] = min(probs);
    action_queue = move_to(neighbors(I)-x, neighbors(I,2)-y, dir);
    last_position = [x, y];
    action = action_queue(1);
    action_taken = action;
    action_queue = action_queue(2:end);
    return
end

%if all neighbors explored, look at neighbors of neighbors for unexplored
if explored == numNeighbors 
    for i = 1:numNeighbors
        neighbors_of_neighbor = BR_Wumpus_neighbors(neighbors(i), neighbors(i, 2));
        [numNeighbors_of_n, numCols] = size(neighbors_of_neighbor);
        for j = 1:numNeighbors_of_n
            if board(4 - neighbors_of_neighbor(j,2) + 1, neighbors_of_neighbor()) == -1
                action_queue = move_to(neighbors(i)-x, neighbors(i,2)-y, dir); 
                last_position = [x, y];
                action = action_queue(1);
                action_taken = action;
                action_queue = action_queue(2:end);
                return
            end
        end
    end

    %no neighbors to explore, go random direction except last position
    goTo = randi(numNeighbors - 1);
    neighbors_not_last = neighbors;
    index=find(ismember(neighbors_not_last,last_position,'rows'));
    neighbors_not_last(index, :) = [];
    last_position = [x, y];
    action_queue = move_to(neighbors_not_last(goTo)-x, neighbors_not_last(goTo,2)-y, dir);
    action = action_queue(1);
    action_taken = action;
    action_queue = action_queue(2:end);
    return
end


%backtrack safely
for i = 1:numNeighbors
    if board(4 - neighbors(i,2) + 1, neighbors(i)) == 0
        action_queue = move_to(neighbors(i)-x, neighbors(i,2)-y, dir);
        last_position = [x, y];
        action = action_queue(1);
        action_taken = action;
        action_queue = action_queue(2:end);
        return
    end
end


%no safe backtrack, move to square with least probability of death
probability_of_death = [2;2;2;2];
for i = 1:numNeighbors
    n_x = 4 - neighbors(i,2) + 1;
    n_y = neighbors(i);
    probability_of_death(i) = wumpus_board(n_x, n_y) +  ...
        pit_board(n_x, n_y);
end

[m, index] = min(probability_of_death); 
action_queue = move_to(neighbors(index)-x, neighbors(index,2)-y, dir);
last_position = [x, y];
action = action_queue(1);
action_taken = action;
action_queue = action_queue(2:end);
return



%returns steps to move to desired neighbor
function actions = move_to(x_dif, y_dif, dir)
actions = [];
dir_goal = 3;
if x_dif == 1
    dir_goal = 0;
elseif x_dif == -1
    dir_goal = 2;
elseif y_dif == 1
    dir_goal = 1;
end

dif = dir - dir_goal;

if dif == 1 || dif == -3
    actions(1) = 2;
elseif dif == -1 || dif == 3
    actions(1) = 3;
elseif dif == 2 || dif == -2
    actions(1) = 3;
    actions(2) = 3;
end

actions(end + 1) = 1;

return
