Finish 2011-04-20 12:00:00 UTC

Weighty matters

by the cyclist

Status: Passed
Results: 8184570 (cyc: 60, node: 1051)
CPU Time: 11.842
Score: 20512.5
Submitted at: 2011-04-14 20:53:45 UTC
Scored at: 2011-04-14 20:57:00 UTC

Current Rank: 1437th (Highest: 75th )
Based on: Seventh heaven (diff)
Basis for: Riffle (diff)
Basis for: NBW Weighty matters (diff)

Comments
Please login or create a profile.
Code
function board = solver(words, weights, n, penalty)

% the cyclist solver
% Copyright 2011 the cyclist, not Inc.

% Determine word lengths
numberWords = length(words);


lengthWords = nan(numberWords,1);
for ii=1:numberWords
    lengthWords(ii) = length(words{ii});
end

% Sort the words in order of descending weight
[weightsAndLengths indexToWeightSorting] = sortrows([weights'./(n+lengthWords) lengthWords],[-1 2]);
% [weightsAndLengths indexToWeightSorting] = sort(weights,2,'descend');

words = words(indexToWeightSorting);
lengthWords = weightsAndLengths(:,2);

% Preallocate the board with zeros
board = zeros(n,n);

% Fill in every other row, beginning with top row. Iterate the following algorithm:
% -- Find highest-weight word that will fit in the line
% -- Place it, with a blank next to i
% -- Repeat

for row = 1:ceil(n/2)
    currentLength = 0;
    
    while (currentLength <= n)
        indexToWordToUse = find(lengthWords<=(n-currentLength),1,'first');
%         indexToWordsThatFit = find(lengthWords<=(n-currentLength));
%         weightOfWordsThatFit = weights(indexToWordsThatFit);
%         indexToMaxWeightFitWords = find(weightOfWordsThatFit==max(weightOfWordsThatFit));
%         lengthMaxWeightFitWords = lengthWords(indexToWordsThatFit(indexToMaxWeightFitWords));
%         [minLengthMaxWeightFitWords indexToMinLengthMaxWeightFitWords] = min(lengthMaxWeightFitWords);
%         indexToWordToUse = indexToWordsThatFit(indexToMaxWeightFitWords(indexToMinLengthMaxWeightFitWords));
        if not(isempty(indexToWordToUse))
            wordToUse = words{indexToWordToUse};
            lengthWords(indexToWordToUse) = Inf;
            lengthWordToUse = numel(wordToUse);
            board(2*row-1,currentLength+1:currentLength+lengthWordToUse) = wordToUse;
            currentLength = currentLength + lengthWordToUse + 1;
        else
            break
        end
    end
    
end

for kk=1:3
% After the above, there will be a ragged right column. Fill down this column with highest-weight words that fit.
blanksInRightmostColumn = find(board(:,n-1)==0&board(:,n)==0&[nan;board(1:n-1,n)]==0&[board(2:n,n);nan]==0);
numberBlanks = numel(blanksInRightmostColumn);
if numberBlanks>0
    lengthToFit = 0;
    anchor = blanksInRightmostColumn(1);
    for nb = 1:numberBlanks-1
        lengthToFit = lengthToFit+1;
        if blanksInRightmostColumn(nb+1)==blanksInRightmostColumn(nb)+1
            continue
        else
            indexToWordToUse = find(lengthWords<=lengthToFit,1,'first');
            if not(isempty(indexToWordToUse))
                wordToUse = words{indexToWordToUse};
                lengthWords(indexToWordToUse) = Inf;
                lengthWordToUse = numel(wordToUse);
                board(anchor:anchor+lengthWordToUse-1,n) = wordToUse;
            end
            anchor = blanksInRightmostColumn(nb+1);
            lengthToFit = 0;
        end
    end
end
end

% Find 3-letter words that we are going to sneak in.
word3Array = words(find(lengthWords==3))';
numberLength3Words = length(word3Array);
word3 = nan(3,numberLength3Words);
for jj=1:numberLength3Words
    word3(:,jj)=word3Array{jj}';
end

% Anywhere we can fit, place a 3-letter word
for row = 1:n-2
for col = 1:n
    if (row==1  ||board(row-1,col  )==0) ...
    && (col==1  ||board(row+1,col-1)==0) && board(row+1,col)==0  && (col==n||board(row+1,col+1)==0) ...
    && (row==n-2||board(row+3,col  )==0)
        topVal = board(row  ,col);
        botVal = board(row+2,col);
        indexToWordToUse = find(word3(1,:)==topVal&word3(3,:)==botVal,1,'first');
        if any(indexToWordToUse)
            board(row+1,col) = word3(2,indexToWordToUse);
            word3(:,indexToWordToUse) = [];
        end
    end
end
end

% Find 5-letter words that we are going to sneak in.
word5Array = words(find(lengthWords==5))';
numberLength5Words = length(word5Array);
word5 = nan(5,numberLength5Words);
for jj=1:numberLength5Words
    word5(:,jj)=word5Array{jj}';
end

% Anywhere we can fit, place a 5-letter word
for row = 1:n-4
for col = 1:n
    if (row==1  ||board(row-1,col  )==0) ...
    && (col==1  ||board(row+1,col-1)==0) && board(row+1,col)==0  && (col==n||board(row+1,col+1)==0) ...
    && (col==1  ||board(row+3,col-1)==0) && board(row+3,col)==0  && (col==n||board(row+3,col+1)==0) ...
    && (row==n-4||board(row+5,col)==0)
        val1 = board(row,  col);
        val3 = board(row+2,col);
        val5 = board(row+4,col);
        indexToWordToUse = find(word5(1,:)==val1 & word5(3,:)==val3 & word5(5,:)==val5,1,'first');
        if any(indexToWordToUse)
            board([row+1 row+3],col) = word5([2 4],indexToWordToUse);
            word5(:,indexToWordToUse) = [];
        end
    end
end
end

% % Find 7-letter words that we are going to sneak in.
% word7Array = words(find(lengthWords==7))';
% numberLength7Words = length(word7Array);
% word7 = nan(7,numberLength5Words);
% for jj=1:numberLength7Words
%     word7(:,jj)=word7Array{jj}';
% end
% 
% % Anywhere we can fit, place a 5-letter word
% for row = 1:n-6
% for col = 1:n
%     if (row==1||board(row-1,col)==0) ...
%     && (col==1||board(row+1,col-1)==0) && board(row+1,col)==0  && (col==n||board(row+1,col+1)==0) ...
%     && (col==1||board(row+3,col-1)==0) && board(row+3,col)==0  && (col==n||board(row+3,col+1)==0) ...
%     && (col==1||board(row+5,col-1)==0) && board(row+5,col)==0  && (col==n||board(row+5,col+1)==0) ...
%     && (row==n-6||board(row+7,col)==0)
%         val1 = board(row,  col);
%         val3 = board(row+2,col);
%         val5 = board(row+4,col);
%         val7 = board(row+6,col);
%         indexToWordToUse = find(word7(1,:)==val1 & word7(3,:)==val3 & word7(5,:)==val5 & word7(7,:)==val7,1,'first');
%         if any(indexToWordToUse)
%             board([row+1 row+3 row+5],col) = word7([2 4 6],indexToWordToUse);
%             word7(:,indexToWordToUse) = [];
%         end
%     end
% end
% end

% Find 2-letter words that we are going to sneak in.
word2Array = words(find(lengthWords==2))';
numberLength2Words = length(word2Array);
word2 = nan(2,numberLength2Words);
for jj=1:numberLength2Words
    word2(:,jj)=word2Array{jj}';
end

% Anywhere there is room, place a stalagmite down from a main row
for row = 1:2:n-3
   indexToTwoSpots = find(board(row+2,:)==0);
   
   for nt = indexToTwoSpots
       if (nt==1||board(row+1,nt-1)==0) && (nt==n||board(row+1,nt+1)==0) && (row==1||board(row-1,nt)==0)
           val1 = board(row,nt);
           indexToLengthTwoWordThatFits = find(word2(1,:)==val1,1,'first');
           if any(indexToLengthTwoWordThatFits)
               board(row:row+1,nt) = word2(:,indexToLengthTwoWordThatFits);
               word2(:,indexToLengthTwoWordThatFits) = [];
           end
       end
   end
end

% Anywhere there is room, place a stalactite up from a main row
for row = 3:2:n
   indexToTwoSpots = find(board(row-2,:)==0);
   
   for nt = indexToTwoSpots
       if (nt==1||board(row-1,nt-1)==0) && (nt==n||board(row-1,nt+1)==0) && (row==n||board(row+1,nt)==0)
           botTwoValue = board(row,nt);
           indexToLengthTwoWordThatFits = find(word2(2,:)==botTwoValue,1,'first');
           if any(indexToLengthTwoWordThatFits)
               board(row-1:row,nt) = word2(:,indexToLengthTwoWordThatFits);
               word2(:,indexToLengthTwoWordThatFits) = [];
           end
       end
   end
end

end