ID:48587
Title:M&M_258
Author:MikeR
Date:2008-05-06 17:54:50
Score:15486.1314
Result:154602.00 (cyc: 11, node: 931)
CPU Time:37.2738
Status:Passed
Comments:
Based on:super speed
Code:
function w = nodespeed(b)
tweak = rand(8,1);

w = solverX(b,78);
s = mygrade(b,w);

nr = size(b,1);

X = b(nr:-1:1,:);
X = X.';

W2 = solverX(X,90);
W2 = [nr-W2(:,2)+1 W2(:,1) nr-W2(:,4)+1 W2(:,3)];
s2 = mygrade(b,W2);

if s>s2
	w=W2;
end
end
function score = mygrade(B,W)
nR=size(B,1);
B(W(:,1)+(W(:,2)-1)*nR)=0;
B(W(:,3)+(W(:,4)-1)*nR)=0;
score=sum(B(:))+size(W,1)+sum(W(:,1)==W(:,3)&W(:,2)==W(:,4))*24;
end

function w = solverX(b,step)
% get pin numbers
p = unique(b(b>0));

% 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 = zeros(1000,2);
[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
mlen=0;
nr = size(bb,1);
zz = rr + (cc-1) * nr;
for k = 1:length(rr)-1
    bestscore = 0;
    minsteps = step;
    for i = order'
        zzi = zz(i);
        if g(zzi)
            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, steps, thisz, stepboard] = findBestMove(bb, g, zzi, minsteps);
        if score > bestscore
            bestscore = score;
            minsteps = steps;
            bestthisz = thisz;
            beststepboard = stepboard;
            if minsteps == 1
                break
            end
        end
    end
    if bestscore == 0 % can't make any more connections (try to add bridges?)
        w = w(1:mlen,:); % offset for padding
        w = [mod(w,nr) ceil(w/nr)]-1;
        w = w(:,[1 3 2 4]);
        return
    end
    bestmove = findPath(zzi, bestthisz, minsteps, beststepboard);
    g = doMove(g, bestmove, bb(bestmove(1)));
    bb = doMove(bb, bestmove, bb(bestmove(1)));
    newlen = size(bestmove,1);
    w(mlen+1:mlen+newlen,:) = bestmove;
    mlen = mlen + newlen;
end
w = w(1:mlen,:); % offset for padding
w = [mod(w,nr) ceil(w/nr)]-1;
w = w(:,[1 3 2 4]);
end


%%
function [bestscore, minsteps, thisz, bb] = findBestMove(b, g, z, steplimit)

bestscore = 0;
minsteps = Inf;
nr = size(b,1);
dz = [1 -1 nr -nr];

if ~any(g(:)==b(z))
    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(z) = 1; % keep track of how many steps it takes to get to each position
nextz=zeros(100,1);
nextz(1)=z;
nextnumrr = 1;
for i = 1:steplimit-1 % only allowed this many steps
    zz = nextz;
    numrr = nextnumrr;
    nextnumrr = 0;
    for n = 1:numrr
        zzn = zz(n);
        for m = 1:4
            thisz = zzn + dz(m);
            if g(thisz) == b(z) && ~(thisz == z)
                minsteps = i; % can link to group in this number of steps
                break
            end
            if bb(thisz) == 0
                bb(thisz) = i + 1;
                nextnumrr = nextnumrr + 1;
                nextz(nextnumrr) = thisz;
            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(z) - minsteps;

end

%%
function bestmove = findPath(z, thisz, minsteps, bb)

% if only one step
if minsteps == 1
    bestmove = [z, thisz];
    return
end

nr = size(bb,1);

% multiple steps - work backwards to define wire from group to pin
dz = [1 -1 nr -nr];
ir = randperm(4);
bestmove = zeros(minsteps,2);
for step = minsteps:-1:1
    for m = 1:4
        nextz = thisz + dz(ir(m));
        if bb(nextz) == step
            break
        end
    end
    bestmove(step,:) = [nextz, thisz];
    thisz = nextz;
end

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)) = v;
end
b(mv(end,2)) = v;

end