creating a list from enumerated facts in prolog

The problem is: We're doing a school test. Given a certain time and points needed, create a list of the possible combinations of questions to achieve the points in the time window.

I have fumbled around with Q, unable to get a list of Q options. I know this one is wrong but I couldn't find the right combination.

The facts are in the format (item number, points, time in minutes to solve the question).

test(1 , 1.5 , 22).
test(2 , 3.0 , 17).
test(3 , 1.5 , 13).
test(4 , 0.5 , 12).
test(5 , 0.5 , 11).
test(6 , 1.5 , 16).
test(7 , 0.5 , 10).
test(8 , 1   , 21).

set(Q, 0, 0) :- !.
set(Q, Points, Time) :- 
   Points > 0, 
   Time > 0, 
   test(Q,P,T), 
   P1 is P - Points, 
   T1 is T - Time, 
   set([Q],P1,T1).

Upvotes: 1

Views: 64

Answers (1)

jf_
jf_

Reputation: 3479

There are a number of issues in your attempt, which I have addressed in the code below:

  • You need a list of tests to keep track of what you've collected (using the backtracking operator in the recursion anchor won't stop the interpreter from choosing the same test again in every step) and another to return the result. An additional parameter is necessary. Then, in every step, \+member(Q,Qs) checks if this test was already selected.
  • To match exactly the points you need a float (0.0) in the anchor
  • The points/time to be used in the next step were calculated in the wrong order, resulting in negative values.
  • Exactly matching points and time might be a very strong requirement. I allowed using less time as an option so that I get some results without testing too much...
set(Qs, 0.0, _, Qs) :- !.
set(Qs, Points, Time, Result) :- 
   Points > 0.0, 
   Time > 0, 
   test(Q,P,T), 
   \+member(Q,Qs),
   T < Time,
   P1 is Points - P, 
   T1 is Time - T, 
   set([Q|Qs],P1,T1, Result).

Sample query with 8 points in 120 minutes gives me the following output (using SWI Prolog). This, of course, can still be improved by sorting the list.

?- set([],8,120,Res).
Res = [8, 5, 4, 3, 2, 1] ;
Res = [6, 4, 3, 2, 1] ;
Res = [8, 7, 4, 3, 2, 1] ;
Res = [5, 8, 4, 3, 2, 1] ;
...

Upvotes: 1

Related Questions