No BSD License  

Highlights from
Countdown Tools

from Countdown Tools by Murphy O'Brien
Tools to find all the solutions to the countdown letters and numbers games.

[equations,answers]=numbersgame(target,numbers,maxerror,allowfractions)
function [equations,answers]=numbersgame(target,numbers,maxerror,allowfractions)
%  function [equations,answers]=numbersgame(target,numbers,[maxerror],[allowfractions])
% solves the countdown numbers game
% e.g.a=numbersgame(715,[1 2 8 6 4 7]
%
%
if nargin<4
    allowfractions=0;
end
if nargin<3
    maxerror=10;
end
numbers=fliplr(sort(numbers(:)'));
vectors=numbers';
for ii=1:length(numbers);
    terms(ii,1)={num2str(numbers(ii))};
end

% now recursively expand to more vectors with fewer terms each by joining pairs of terms
for ii=1:length(numbers)-2;
    [vectors,terms]=expand(vectors,terms,allowfractions);
end

% break the final expansion up into 4 smaller pieces for memory reasons
st=floor(size(vectors,2)/4);
termsA=terms(:,1:st);
vectorsA=vectors(:,1:st);
termsB=terms(:,st+1:2*st);
vectorsB=vectors(:,st+1:2*st);
termsC=terms(:,2*st+1:3*st);
vectorsC=vectors(:,2*st+1:3*st);
terms=terms(:,3*st+1:end);
vectors=vectors(:,3*st+1:end);

% expand first quarter
[vectors,terms]=expand(vectors,terms,allowfractions);
equations={};
maxe=200000*eps;
while isempty(equations) & (maxe<=maxerror+100*eps)
    equations=terms(abs(target-vectors)<=maxe)';
    answers=vectors(abs(target-vectors)<=maxe);
    maxe=maxe+1;
end
clear terms vectors

% expand next quarter
[vectorsA,termsA]=expand(vectorsA,termsA,allowfractions);
equationsA={};
maxeA=200000*eps;
while isempty(equationsA) & (maxeA<=maxe-1+100*eps)
    equationsA=termsA(abs(target-vectorsA)<=maxeA)';
    answersA=vectorsA(abs(target-vectorsA)<=maxeA);
    maxeA=maxeA+1;
end
clear termsA vectorsA
if maxeA==maxe
    equations=unique([equations;equationsA]);
    answers=[answers answersA];
else
    equations=equationsA;
    answers=answersA;
end


% expand next quarter
[vectorsB,termsB]=expand(vectorsB,termsB,allowfractions);
equationsB={};
maxeB=200000*eps;
while isempty(equationsB) & (maxeB<=maxeA-1+100*eps)
    equationsB=termsB(abs(target-vectorsB)<=maxeB)';
    answersB=vectorsB(abs(target-vectorsB)<=maxeB);
    maxeB=maxeB+1;
end
clear termsB vectorsB
if maxeB==maxeA
    equations=unique([equations;equationsB]);
    answers=[answers answersB];
else
    equations=equationsB;
    answers=answersB;
end


% expand last quarter
[vectorsC,termsC]=expand(vectorsC,termsC,allowfractions);
equationsC={};
maxeC=200000*eps;
while isempty(equationsC) & (maxeC<=maxeB-1+100*eps)
    equationsC=termsC(abs(target-vectorsC)<=maxeC)';
    answersC=vectorsC(abs(target-vectorsC)<=maxeC);
    maxeC=maxeC+1;
end
if maxeC==maxeB
    equations=unique([equations;equationsC]);
    answers=[answers answersC];
else
    equations=equationsC;
    answers=answersC;
end



if ~isempty(answers) && all(abs(answers-answers(1))<200000*eps)
    answers=answers(1);                     % make only one answer, if all same
end 

return


%
% function which takes all possible pairs of terms in the 
% input matrix and combines in all possible way to get an
% more vectors each with one less term.
% 
function [vectorsout,termsout]=expand(vectorsin,termsin,allowfractions)
[nnum,nvec]=size(vectorsin);
newsize=nvec*(4*nnum*(nnum-1)/2+nnum);
vectorsout=zeros(nnum-1,newsize);
termsout=cell(size(vectorsout));
index=0;
pluses=repmat('+',1,nvec);
minuses=repmat('-',1,nvec);
lbrackets=repmat('(',1,nvec);
rbrackets=repmat(')',1,nvec);
multiplies=repmat('x',1,nvec);
divides=repmat('/',1,nvec);

    for i1=1:nnum
        n1=vectorsin(i1,:);                                             % first number of pair
        term1=termsin(i1,:);
        term1=char(term1{:}).';
        for i2=i1+1:nnum
            n2=vectorsin(i2,:);                                         % second number of pair
            term2=termsin(i2,:);
            term2=char(term2{:}).';
            othernums=vectorsin([1:i1-1,i1+1:i2-1,i2+1:nnum],:);
            otherterms=termsin([1:i1-1,i1+1:i2-1,i2+1:nnum],:);
            for operator='+-*/'
                switch operator
                    case '+'
                        answer=n1+n2;
                        term=cellstr([lbrackets;term1;pluses;term2;rbrackets]');
                        term=strrep(term,' ','')';
                        valid=true(1,size(term,2));
                    case '-'
                        answer=n1-n2;
                        term=cellstr([lbrackets;term1;minuses;term2;rbrackets]');
                        valid=(answer>0);
                        term=strrep(term(valid),' ','')';
                        answer=answer(valid);     % remove non integer results
                    case '*'
                        answer=n1.*n2;
                        term=cellstr([term1;multiplies;term2]');
                        valid=(n2>1);
                        term=strrep(term(valid),' ','')';
                        answer=answer(valid);     % remove non integer results
                    case '/'
                        answer=n1./n2;
                        term=cellstr([term1;divides;term2]');
                        valid=(allowfractions|((answer-floor(answer))==0))&(n2>1);
                        term=strrep(term(valid),' ','')';
                        answer=answer(valid);     % remove non integer results
                end     % end switch
                nvl=size(term,2);
                if nvl>0
                    vectorsout(:,index+1:index+nvl)=[answer; othernums(:,valid)];
                    termsout(:,index+1:index+nvl)=[term; otherterms(:,valid)];
                    index=index+nvl;
                end
            end         % next operator
        end             % next n2
        clear term2;
        othernums=vectorsin([1:i1-1,i1+1:nnum],:);
        otherterms=termsin([1:i1-1,i1+1:nnum],:);
        vectorsout(:,index+1:index+nvec)=othernums;
        termsout(:,index+1:index+nvec)=otherterms;
        index=index+nvec;
    end % next n1
clear term1 otherterms termsin;
% sort new numbers in each vector with biggest first
[vectorsout,isort]=sort(vectorsout(:,1:index),1,'descend');
% now copy all the terms with the vector sorting indices
terms=termsout(:,1:index);
for ii=1:index;
    terms(:,ii)=termsout(isort(:,ii),ii);
end
termcat=cell(size(terms,2),1);
for ii=1:size(terms,2);
    termcat(ii)={[terms{:,ii}]};                 % concatenate all terms in each vector to allow UNIQUE sets of terms to be found
end
[garbage,isort]=unique(termcat);
vectorsout=vectorsout(:,isort);
termsout=terms(:,isort);

Contact us at files@mathworks.com