2013 LP Programming Contest


icecream.pi

 
main => test.

test => icecream(5).

icecream(N) =>
    Margin = N,
    printf("%*s()\n",Margin,""),
    Spaces = 0,
    foreach(I in 1..N)
        Margin := Margin-1,
        printf("%*s((%*s))\n",Margin,"",Spaces,""),
	Spaces := Spaces+2
    end,
    foreach(I in 1..N+1) print("/\\") end,
    nl,
    Margin := 0,
    Spaces := N*2,
    foreach(I in 1..N+1)
        printf("%*s\\%*s/\n",Margin,"",Spaces,""),
        Spaces := Spaces-2,
	Margin := Margin+1
    end.

queens.pi

 
import sat.

main => test.

test =>
    evil_and_nice(8,Evil,Nice),
    writeln($evil(Evil)),
    writeln($nice(Nice)).

evil_and_nice(N,Evil,Nice) =>
    QB = new_array(N,N),  % Bad (evial) queens
    QG = new_array(N,N),  % Good (nice ) queens
    QB :: 0..1,
    QG :: 0..1,
    NQB :: 1..N,
    sum([QB[I,J] : I in 1..N, J in 1..N]) #= NQB,
    sum([QG[I,J] : I in 1..N, J in 1..N]) #= NQG,
    abs(NQG-NQB) #=< 1,
    foreach(I in 1..N, J in 1..N, I1 in 1..N, J1 in 1..N) 
        if (I==I1 || J==J1 || I+J==I1+J1 || I-J == I1-J1) then
            if (I,J) != (I1,J1) then QB[I,J] #=> #~ QB[I1,J1] end,
            QB[I,J] #=> #~ QG[I1,J1]
        end
    end,
    solve([$max(NQB+NQG)],(QB,QG)),
    Evil = [$pos(I,J) : I in 1..N, J in 1..N, QB[I,J]==1],
    Nice = [$pos(I,J) : I in 1..N, J in 1..N, QG[I,J]==1].    

arith.pi

 
main => test.

test =>
    maxval($tree(tree(6,8),tree(2,2)), [mult, mult, plus], Max),
    writeln(Max).

test2 =>
    maxval($tree(tree(6,8),tree(2,2)), [mult, min, plus], Max),
    writeln(Max).

maxval(Tree,Ops,Val) =>
    maxval(Tree,Ops,_,Val).

table (+,+,-,max)
maxval(Tree,Ops,OpsO,Val),integer(Tree) => Val=Tree,OpsO=Ops.
maxval(tree(T1,T2),Ops,OpsO,Val) ?=>
    select(Op,Ops,Ops1),
    minval(T1,Ops1,Ops2,V1),
    minval(T2,Ops2,OpsO,V2),
    app(Op,V1,V2) = Val.
maxval(tree(T1,T2),Ops,OpsO,Val) ?=>
    select(Op,Ops,Ops1),
    minval(T1,Ops1,Ops2,V1),
    maxval(T2,Ops2,OpsO,V2),
    app(Op,V1,V2) = Val.
maxval(tree(T1,T2),Ops,OpsO,Val) ?=>
    select(Op,Ops,Ops1),
    maxval(T1,Ops1,Ops2,V1),
    minval(T2,Ops2,OpsO,V2),
    app(Op,V1,V2) = Val.
maxval(tree(T1,T2),Ops,OpsO,Val) =>
    select(Op,Ops,Ops1),
    maxval(T1,Ops1,Ops2,V1),
    maxval(T2,Ops2,OpsO,V2),
    app(Op,V1,V2) = Val.

table (+,+,-,min)
minval(Tree,Ops,OpsO,Val),integer(Tree) => Val=Tree,OpsO=Ops.
minval(tree(T1,T2),Ops,OpsO,Val) ?=>
    select(Op,Ops,Ops1),
    minval(T1,Ops1,Ops2,V1),
    minval(T2,Ops2,OpsO,V2),
    app(Op,V1,V2) = Val.
minval(tree(T1,T2),Ops,OpsO,Val) ?=>
    select(Op,Ops,Ops1),
    minval(T1,Ops1,Ops2,V1),
    maxval(T2,Ops2,OpsO,V2),
    app(Op,V1,V2) = Val.
minval(tree(T1,T2),Ops,OpsO,Val) ?=>
    select(Op,Ops,Ops1),
    maxval(T1,Ops1,Ops2,V1),
    minval(T2,Ops2,OpsO,V2),
    app(Op,V1,V2) = Val.
minval(tree(T1,T2),Ops,OpsO,Val) =>
    select(Op,Ops,Ops1),
    maxval(T1,Ops1,Ops2,V1),
    maxval(T2,Ops2,OpsO,V2),
    app(Op,V1,V2) = Val.

app(plus,V1,V2) = V1+V2.
app(min,V1,V2) = V1-V2.
app(mult,V1,V2) = V1*V2.

domain.pi

 
import cp.

main => test.

test => test1.

test1 => domain([X,Y],$[X+Y = 2],[-1006,1006],Domain), writeln(Domain).
% Domain = [1,1]
test2 => domain([X,Y],$[X+Y = 0, X*Y = -1, X > 0],[-500,500],Domain), writeln(Domain).
% Domain = [-1,1]
test3 => domain([X,Y],$[X+Y=1],[-1000,1000],Domain), writeln(Domain).
% No % because no domain has a unique solution
test4 => domain([X,Y],$[X*Y = 3, X > 1, Y > 1],[-1000,1000],Domain),writeln(Domain).
% No % because there is no solution for any domain
test5 => domain([X,Y],$[X-Y=0],[-2020,-20],Domain),writeln(Domain).
% Domain = [-666,-666] % just one of the many correct answers

domain(Vs,Cs,Domain0,Domain) =>
    initialize_table,
    csp(Domain0,Domain,_,(Vs,Cs)).

table (+,+,min,nt)
csp(Domain0@[L,U],Domain,Size,CSP),
    solve_csp0(CSP,Domain0,Count)
=>
    (    Count == 1, Domain = Domain0, Size = U-L+1
     ;
         L1 = L+1, L1 <= U,
         csp([L1,U],Domain,Size,CSP)
     ;	    
         U1 = U-1, L < U1,
         csp([L,U1],Domain,Size,CSP)
    ).

solve_csp0((Vs,Cs),[L,U],_Count) ?=>
    get_global_map().clear(),
    once(solve_csp(Vs,Cs,L,U)),
    fail.
solve_csp0(_CSP,_Domain,Count) =>
    M = get_global_map(),
    M.has_key(count),
    Count = M.get(count).
    
solve_csp(Vs,Cs,L,U) =>
    Vs :: L..U,
    post_cs(Cs),
    M = get_global_map(),
    solve(Vs),
    (M.has_key(count) ->
        M.put(count,2)
    ;
        M.put(count,1),
        fail
    ).
         			  
post_cs([]) => true.
post_cs([V1+V2=I|Cs]) =>
    V1+V2 #= I,
    post_cs(Cs).
post_cs([V1-V2=I|Cs]) =>
    V1-V2 #= I,
    post_cs(Cs).
post_cs([V1*V2=I|Cs]) =>
    V1*V2 #= I,
    post_cs(Cs).
post_cs([V1>V2|Cs]) =>
    V1 #> V2,
    post_cs(Cs).
post_cs([V1<V2|Cs]) =>
    V1 #< V2,
    post_cs(Cs).

travel.pi

 
main => test.

test =>
    maximalpleasure($[journey(bozo,[heverlee, bertem, tervuren]),
		     journey(bozo,[heverlee, korbeekdijle, tervuren]),
		     journey(dork,[hammemille, korbeekdijle, tervuren, sterrebeek]),
		     journey(dork,[hammemille, overijse, tervuren, sterrebeek])],
		    10,3,P),
    writeln(P).

maximalpleasure(Js,PDay,PNight,P) =>
    Ts = [T : $journey(T,_) in Js],
    sort_remove_dups(Ts) = Ts1,
    mp(Ts1,_,P,(Js,PDay,PNight)).

table (+,-,max,nt)
mp([],Plans,P,_) => Plans=[],P=0.
mp([T|Ts],Plans,P,GData@(Js0,PDay,PNight)) =>
    Plans=[Plan|Plans1],
    member($journey(T,Plan),Js0),
    mp(Ts,Plans1,P1,GData),
    P = P1+sum([pleasure(Plan,Plan1,PDay,PNight) : Plan1 in Plans1]).

pleasure([],_,_PDay,_PNight) = 0.
pleasure([_],_,_PDay,_PNight) = 0.
pleasure(_,[],_PDay,_PNight) = 0.
pleasure(_,[_],_PDay,_PNight) = 0.
pleasure([From,To|J],[From,To|J1],PDay,PNight) = 2*PDay+2*PNight+pleasure([To|J],[To|J1],PDay,PNight).
pleasure([_,To|J],[_,To|J1],PDay,PNight) = 2*PNight+pleasure([To|J],[To|J1],PDay,PNight).
pleasure([_,To|J],[_,To1|J1],PDay,PNight) = pleasure([To|J],[To1|J1],PDay,PNight).