:- table match/3. :- table sum/5. % Number of card X = Nx = 1 + sum(Ni*(matches(i) >= x-i), i=1->x-1) ncards([], []). ncards([_|RestOfCards], [Nx|NRest]) :- length(RestOfCards, X_minus_1), X is X_minus_1 + 1, ncards(RestOfCards, NRest), reverse(RestOfCards, ReversedRestOfCards), sum(ReversedRestOfCards, X, NRest, _, Nx_minus_1), Nx is Nx_minus_1 + 1. % sum(Cards, X, StuffToSum, Indices, Sum). % This calculates the "sum(Ni*(matches(i) >= x-i), i=1->x-1)" part of Nx sum(_, _, [], [0], 0). sum(Cards, X, [Element|Rest], [I,INext|IRest], Sum) :- sum(Cards, X, Rest, [INext|IRest], SumOfRest), match(Cards, I, NMatches_i), I is INext + 1, (NMatches_i >= X - I -> Sum is Element + SumOfRest; Sum is SumOfRest). % match binds the number of matches that card Nth in the list has match(Cards, Nth, NMatches) :- nth1(Nth, Cards, [Wins|CardNums]), match1(Wins, CardNums, NMatches). % match1(WinningNums, CardNums, NMatches) binds number of matches for a card. match1(_, [], 0). match1(Wins, [X|Nums], M) :- member(X, Wins), match1(Wins, Nums, M1), M is M1 + 1. match1(Wins, [X|Nums], M) :- \+ member(X, Wins), match1(Wins, Nums, M). % this is a more normal sum of a list sum([], 0). sum([Element|Rest], Sum) :- sum(Rest, RestOfSum), Sum is Element + RestOfSum. all_scores(Input, Score) :- reverse(Input, ReversedInput), ncards(ReversedInput, CardCounts), sum(CardCounts, Score).