Code covered by the BSD License  

Highlights from
MATLAB Contest - Army Ants

from MATLAB Contest - Army Ants by The MATLAB Contest Team
All the files needed to develop and score an entry for the MATLABĀ® Programming Contest.

armyantsimulator(contestAntFH,houseAntFH,problem,drawboard)
function food = armyantsimulator(contestAntFH,houseAntFH,problem,drawboard)
% MATLAB 2008 Army Ants Contest
%
% RESULT = ARMYANTSIMULATOR(contestAntFH,houseAntFH,problem,drawboard)
%
%   contestAntFH - function handle to the contest"ANT" microprogram
%   houseAntFH   - function handle to the "king of the hill" microprogram
%   problem      - structure with the fields: main, food, red, black,
%                  redScent, blackScent, redDeath, blackDeath
%   drawboard    - logical flag to show the map

% Copyright 2008 The MathWorks, Inc.

if nargin<4
    drawboard = true;
end

main       = problem.main;
food       = problem.food;
red        = problem.red;
black      = problem.black;
redScent   = zeros(size(main));
blackScent = zeros(size(main));
redDeath   = zeros(size(main));
blackDeath = zeros(size(main));

if drawboard
    viewantmap(main,food,red,black,redScent,blackScent,redDeath,blackDeath,true)
end

for timeStep = 1:1000
    
    mergeList = getMergeList(red, black);
    if ~isstruct(mergeList) && isnan(mergeList)
        return
    end
    
    actions = getActions(mergeList, main, food, red, black, redScent, blackScent, redDeath, blackDeath, contestAntFH, houseAntFH);
    
    [main, food, red, black, redScent, blackScent, redDeath, blackDeath] = ...
        updateWorld(actions, main, food, red, black, redScent, blackScent, redDeath, blackDeath, mergeList);
    
    if drawboard
        viewantmap(main,food,red,black,redScent,blackScent,redDeath,blackDeath,false,timeStep)
    end
    
end

end


function actions = getActions(mergeList, main, food, red, black, redScent, blackScent, redDeath, blackDeath, contestAntFH, houseAntFH)
actions(numel(mergeList)).r = [];  %preallocate

for curAnt = 1 : numel(mergeList)
    
    [AVmain, AVfood, AVred, AVblack, AVredScent, AVblackScent, AVredDeath, AVblackDeath] = ...
        getAntView(mergeList(curAnt),main, food, red, black, redScent, blackScent, redDeath, blackDeath);
    
    if mergeList(curAnt).team == 'r'    
        [actions(curAnt).dRow, actions(curAnt).dCol, actions(curAnt).action, actions(curAnt).mark] ...
            = contestAntFH(-AVmain, AVfood, AVred, AVblack, AVredScent, AVblackScent, AVredDeath, AVblackDeath);
    else
        try
        [actions(curAnt).dRow, actions(curAnt).dCol, actions(curAnt).action, actions(curAnt).mark] ...
            = houseAntFH(AVmain, AVfood, AVblack, AVred, AVblackScent, AVredScent, AVblackDeath, AVredDeath);
        catch %#ok<CTCH>
            actions(curAnt).dRow = 0;
            actions(curAnt).dCol = 0;
            actions(curAnt).action = 0;
            actions(curAnt).mark = 0;
        end
    end
    
    % actions(curAnt) = safeCheckAction(actions(curAnt)); %CHECK TOO SLOW.
    % TOO BAD IF YOUR INPUTS BUST CODE
    
    actions(curAnt).team = mergeList(curAnt).team;
    actions(curAnt).r    = mergeList(curAnt).r;
    actions(curAnt).c    = mergeList(curAnt).c;
end

end

function [main, food, red, black, redScent, blackScent, redDeath, blackDeath] = ...
        updateWorld(actions, main, food, red, black, redScent, blackScent, redDeath, blackDeath, mergeList)

    %pharamone phase
    for curAnt = 1 : numel(mergeList)
        [redScent, blackScent] = pharamoneDrop(actions(curAnt), redScent, blackScent);
    end
    
    %move phase
    for curAnt = 1 : numel(mergeList)
        [red, black, food, actions(curAnt)] = moveAnt(actions(curAnt), food, red, black, main);
    end

    
    %attack and death phase
    for curAnt = 1 : numel(mergeList)
        [red, black, redDeath, blackDeath] = attackAnt(actions(curAnt), red, black, redDeath, blackDeath);

    end
    
    %lessen pharamone and deaths head
      redDeath = max(  redDeath-1, 0);
    blackDeath = max(blackDeath-1, 0);
      redScent = max(  redScent-1, 0);
    blackScent = max(blackScent-1, 0);
end

function [redScent, blackScent] = pharamoneDrop(action, redScent, blackScent)
    if action.mark < 0
        action.mark = 0;
    elseif action.mark > 100
        action.mark = 100;
    end
    
    action.mark = round(action.mark);
    
    if action.team == 'r'
          redScent(action.r, action.c) =   redScent(action.r, action.c) + action.mark;
    end

    if action.team == 'b'
        blackScent(action.r, action.c) = blackScent(action.r, action.c) + action.mark;
    end
end

function [red, black, food, action] = moveAnt(action, food, red, black, main)
    flagGoodRow =  (action.dRow == -1) |...
                   (action.dRow ==  0) |...   
                   (action.dRow ==  1);
    flagGoodCol =  (action.dCol == -1) |...
                   (action.dCol ==  0) |...   
                   (action.dCol ==  1);

    if (flagGoodRow && flagGoodCol)               
        newR = action.r + action.dRow;
        newC = action.c + action.dCol;
    
        if ~isnan(main(newR, newC)) %not obstacle
            
            if (action.action == 1) && ...
               (food(action.r, action.c) > 0) %carry and there is food
            food(action.r, action.c) = food(action.r, action.c) - 1;
            food(newR, newC) = food(newR, newC) + 1;
            end %move sugar
            
            if action.team == 'r'
                red  (action.r, action.c) = red  (action.r, action.c) - 1;
                red  (newR,newC) = red  (newR,newC) + 1;
            end
            
            if action.team == 'b'
                black(action.r, action.c) = black(action.r, action.c) - 1;
                black(newR,newC) = black(newR,newC) + 1;
            end
            
            action.r = newR; %move ant
            action.c = newC; %move ant
        end
    else %not a good move
        return
    end
end

function [red, black, redDeath, blackDeath] = attackAnt(actions, red, black, redDeath, blackDeath)
    if (actions.dRow   ==   0) && ...
       (actions.dCol   ==   0) && ...
       (actions.action ==  -1) %Not moving, and attacking
   
        if     (actions.team == 'r') && (black(actions.r, actions.c) > 0)
            black     (actions.r, actions.c) = black     (actions.r, actions.c) -   1;
            blackDeath(actions.r, actions.c) = blackDeath(actions.r, actions.c) + 100;
            
        elseif (actions.team == 'b') && (  red(actions.r, actions.c) > 0)
              red     (actions.r, actions.c) =   red     (actions.r, actions.c) -   1;
              redDeath(actions.r, actions.c) =   redDeath(actions.r, actions.c) + 100;
        end
    end
end
            


function [AVmain, AVfood, AVred, AVblack, AVredScent, AVblackScent, AVredDeath, AVblackDeath]...
        = getAntView(currA, main, food, red, black, redScent, blackScent, redDeath, blackDeath)
    dist = [-2 -1 0 1 2];
    dr = currA.r + dist;
    dc = currA.c + dist;
    AVmain       = main      (dr, dc);
    AVfood       = food      (dr, dc);
    AVred        = red       (dr, dc);
    AVblack      = black     (dr, dc);
    AVredScent   = redScent  (dr, dc);
    AVblackScent = blackScent(dr, dc);
    AVredDeath   = redDeath  (dr, dc);
    AVblackDeath = blackDeath(dr, dc);
end

function viewantmap(main,food,red,black,redScent,blackScent,redDeath,blackDeath,reset, timeStep)

% shows the ant maps in a MATLAB figure
f = findobj(0,'Tag','AntMap');
if reset || isempty(f) % create new one
    
    if isempty(f)
        f = figure('Tag','AntMap');
    else % reuse old AntMap figure
        clf 
        figure(f)
    end
    
    cMap = flipud(pink(100));
    cMap = cMap(1:75,:);
    colormap(cMap)

    topScent = max([redScent(:); blackScent(:); 1]);
    
    handle.axisrs = subplot(2,2,1);
    handle.imagers = imagesc(redScent);
    title('Scent Red')
    [handle.blackants{1} handle.redants{1} handle.food(1,:)] = showFeatures(main, food, red, black);

    handle.axisbs = subplot(2,2,2);
    handle.imagebs = imagesc(blackScent);
    title('Scent Black')
    [handle.blackants{2} handle.redants{2} handle.food(2,:)] = showFeatures(main, food, red, black);

    topDeath = max([redDeath(:); blackDeath(:); 1]);

    handle.axisrd = subplot(2,2,3);
    handle.imagerd = imagesc(redDeath);
    set(handle.axisrd, 'clim',[0 topDeath])
    title(['Death Red, with ' num2str(sum(red(:))) ' red ants alive.'])
    [handle.blackants{3} handle.redants{3} handle.food(3,:)] = showFeatures(main, food, red, black);

    handle.axisbd = subplot(2,2,4);
    handle.imagebd = imagesc(blackDeath);
    set(handle.axisbd, 'clim',[0 topDeath])
    title(['Death Black, with ' num2str(sum(black(:))) ' black ants alive.'])
    [handle.blackants{4} handle.redants{4} handle.food(4,:)] = showFeatures(main, food, red, black);

    setappdata(f,'AntHandles',handle)
    set(f,'MenuBar','none')
    drawnow

else % AntMap exists, then just update

    handle = getappdata(f,'AntHandles');
    [xx,yy] = getSpots(black);
    set(cell2mat(handle.blackants),'Xdata',xx,'Ydata',yy+.25)
    [xx,yy] = getSpots(red);
    set(cell2mat(handle.redants),'Xdata',xx,'Ydata',yy-.25)
    set(handle.food(:),'string','');
    for i = find(food)'
        set(handle.food(:,i),'string',num2str(food(i)))
    end
    topScent = max([redScent(:); blackScent(:); 1]);
    topDeath = max([redDeath(:); blackDeath(:); 1]);
    set([handle.axisrd handle.axisbd], 'clim',[0 topDeath])
    set(handle.imagers,'Cdata',redScent)
    set(handle.imagebs,'Cdata',blackScent)
    set(handle.imagerd,'Cdata',redDeath)
    set(handle.imagebd,'Cdata',blackDeath)
    axes(handle.axisrd)
    title(['Death Red' char(10) 'with ' num2str(sum(red(:))) ' red ants alive at time ' num2str(timeStep) '.'])
    axes(handle.axisbd)
    title(['Death Black' char(10) 'with ' num2str(sum(black(:))) ' black ants alive at time ' num2str(timeStep) '.'])
    drawnow
end

end


function [blackantsHandle,redantsHandle,foodHandle] = showFeatures(main, food, red, black)
[obsY, obsX] = find(isnan(main));
patch(bsxfun(@plus,obsX,[-0.5 0.5 0.5 -0.5])',bsxfun(@plus,obsY,[0.5 0.5 -0.5 -0.5])','k');

[hy, hx] = find(main == -1); % red anthill
line(hx, hy,'marker','^','color',[1 0 0],'linestyle','none')

[hy, hx] = find(main == 1); % black anthill
line(hx, hy,'marker','^','color',[0 0 0],'linestyle','none')

[sy, sx] = find(ones(size(food))); % sugar
foodHandle = text(sx-.4,sy,'');
for i = find(food)'
    set(foodHandle(i),'string',num2str(food(i)))
end

[xx,yy]=getSpots(black);
blackantsHandle = line(xx,yy+.25,'marker','.','color','k','linestyle','none');
[xx,yy]=getSpots(red);
redantsHandle = line(xx,yy-.25,'marker','.','color','r','linestyle','none');

numRows = size(main,1); 
numCols = size(main,2);
line(repmat([0;numCols+1]-0.5,1,numRows+1),[0:numRows;0:numRows]+.5,'color',[0.8 0.8 0.8])
line([0:numCols;0:numCols]+.5,repmat([0;numRows+1]-0.5,1,numCols+1),'color',[0.8 0.8 0.8])

end

function [xx,yy] = getSpots(A)
[q,r] = find(A);
m = nonzeros(A);
if isempty(m)
    xx=[];yy=[];
    return
end
n = sum(m);
o = cumsum([0;m(1:end-1)])+1;
u = zeros(n,1);u(o) = 1;
v = zeros(n,1);v(o) = -[0;m(1:end-1)];
w = v; w(o) = w(o)+m;
u = cumsum(u);
v = cumsum(1+v)-1;
w = cumsum(w)-1;
xx = r(u)+min(.8./w,1).*v+.1+(w==0).*.4-.5;
yy = q(u);
end
    
function mergeList = getMergeList(red, black)

      redList = antMat2List(  red);
    blackList = antMat2List(black);
    mergeList = lists2mergeList(redList, blackList);
end

function   list = antMat2List(inMat)
    if nnz(inMat) == 0;
        list = [];
        return
    end
    
    numAnts = sum(inMat(:));
    list(numAnts).r = []; %preallocate
    for i = 1:numAnts
        [r,c] = find(inMat,1);
        list(i).r = r;
        list(i).c = c;
        inMat(r,c) = inMat(r,c) - 1;
    end
end

function mergeList = lists2mergeList(redList, blackList)

    finished = 0;
    i = 1;
    totalNum = numel(redList) + numel(blackList);
    
    if totalNum == 0
        mergeList = nan;
        return
    end
    mergeList(totalNum).team = [];  %preallocate
    mergeList(totalNum).r    = [];  %preallocate
    mergeList(totalNum).c    = [];  %preallocate

        ri = 1;
        bi = 1;
      rMax = numel(  redList);
      bMax = numel(blackList);
      
    while ~finished


        if ri <= rMax
            mergeList(i).team = 'r';
            mergeList(i).r    =   redList(ri).r;
            mergeList(i).c    =   redList(ri).c;
            ri = ri + 1;
            i = i+1;
        end
         
        if bi <= bMax
            mergeList(i).team = 'b';
            mergeList(i).r    = blackList(bi).r;
            mergeList(i).c    = blackList(bi).c;
            bi = bi + 1;
            i = i+1;
        end
        
        if ((ri > rMax) && (bi > bMax))
            finished = 1;
        end
    end
end

function actions = safeCheckAction(actions)

if isempty(actions.dRow) || ...
   isempty(actions.dCol) || ...
   isempty(actions.action)

actions.dRow   = 0;
actions.dCol   = 0;
actions.action = 0;
return
end

if ~ismember(actions.dRow  , [-1 0 1]) || ...
   ~ismember(actions.dCol  , [-1 0 1]) || ...
   ~ismember(actions.action, [-1 0 1])

actions.dRow   = 0;
actions.dCol   = 0;
actions.action = 0;

end
end



Contact us at files@mathworks.com