ID:46216
Title:minsteps15
Author:Steve Hoelzer
Date:2008-05-02 11:50:37
Score:16082.4025
Result:160474.00 (cyc: 16, node: 631)
CPU Time:39.7836
Status:Passed
Comments:
Based on:none
Code:
function w = solver(b)

% get pin numbers
p = unique(b);
p(1) = []; % discard zero

% count number of each pin
n = zeros(size(p));
for i = 1:length(n)
    n(i) = nnz(p(i) == b(:));
end

% ignore single pins since they can't be connected to anything
for i = 1:length(n)
    if n(i) == 1
        b(p(i) == b(:)) = -1;
    end
end

% pad board so I don't have to deal with out of bounds indexing
g = zeros(size(b)+2); % board to keep track of groups
bb = repmat(-1,size(g));
bb(2:end-1,2:end-1) = b; % full board

% loop to choose move and do it
w = [];
[rr, cc] = find(bb>0); % pins I want to connect
d = (size(bb,1)/2 - rr).^2 + (size(bb,2)/2 - cc).^2;
[d, order] = sort(d); % start in center of board and work out
for k = 1:length(rr)-1
    bestscore = 0;
    minsteps = 100;
    for i = order'
        if g(rr(i), cc(i))
            continue % this pin is already in a group, so don't try to connect
        end
        % find best route from pin to pin's group
        [score, mv, steps] = findBestMove(bb, g, rr(i), cc(i), minsteps);
        if score > bestscore
            bestscore = score;
            bestmove = mv;
            minsteps = steps;
            if minsteps == 1
                break
            end
        end
    end
    if bestscore == 0 % can't make any more connections (try to add bridges?)
        w = w - 1; % offset for padding
        return
    end
    g = doMove(g, bestmove, bb(bestmove(1,1), bestmove(1,2)));
    bb = doMove(bb, bestmove, bb(bestmove(1,1), bestmove(1,2)));
    w = [w; bestmove];
end

w = w - 1; % offset for padding


%%
function [bestscore, bestmove, minsteps] = findBestMove(b, g, r, c, steplimit)

bestscore = 0;
bestmove = [];

j = [1 -1 0 0];
k = [0 0 1 -1];

if ~any(g(:)==b(r,c))
    g = b; % no groups for this pin yet, so all pins are valid
end

% start at (r,c) pin and step away one unit at a time looking for this pin's group
bb = b;
bb(bb>0) = -1;
bb(r,c) = 1; % keep track of how many steps it takes to get to each position
minsteps = Inf;
for i = 1:steplimit % only allowed this many steps
    [rr, cc] = find(bb==i);
    for n = 1:length(rr)
        for m = 1:4
            thisr = rr(n) + j(m);
            thisc = cc(n) + k(m);
            v = g(thisr,thisc);
            if v == b(r,c) && ~(thisr == r && thisc == c)
                minsteps = i; % can link to group in this number of steps
                break
            end
            v = bb(thisr,thisc);
            if v == 0
                bb(thisr,thisc) = i+1;
            end
        end
        if minsteps < Inf
            break
        end
    end
    if minsteps < Inf
        break
    end
end
if minsteps == Inf
    return % can't reach any pins (good candidate for a bridge)
end

% score for this connection
bestscore = b(r,c) - minsteps;

% if only one step
if minsteps == 1
    bestmove = [r, c, thisr, thisc];
    return
end

% multiple steps - work backwards to define wire from group to pin
bestmove = zeros(minsteps,4);
for step = minsteps:-1:1
    for m = 1:4
        nextr = thisr + j(m);
        nextc = thisc + k(m);
        if bb(nextr, nextc) == step
            break
        end
    end
    bestmove(step,:) = [nextr, nextc, thisr, thisc];
    thisr = nextr;
    thisc = nextc;
end


%%
function b = doMove(b, mv, v)

% mark wires with the same number as the pins
for i = 1:size(mv,1)
    b(mv(i,1), mv(i,2)) = v;
end
b(mv(end,3), mv(end,4)) = v;