Я сделал программу пролога, чтобы показать мне, как лучше всего размещать материалы на DVD. Вопросы находятся в комментариях к коду для справки, который я вставлю ниже, но все сводится к следующему:
Is there a sort of inverted cut operator to make it search for more although it already matches? See fitexact, something like fitexact(Size,Sum,L,L):-Sum
What's the best way to keep track of already processed movies? I retract them but wonder how to do it without that.
fitfuzzy использует конструкцию
if
then
. Я не уверен, что о них думать, это странно в прологе. Однако попытка сделать его рекурсивным оставила меня ужасно сбитым с толку :)
% given a list of movies and sizes, try to fit them all onto dvd's % wasting as little space as possible. % set the dvd size dvdsize(4812). % sum of all movies in the db movies_size(Size) :- findall(S, movie(_,S), LS), sum_list(LS,Size). % count of all movies in the db movies_count(Count) :- findall(S, movie(_,S), LS), length(LS,Count). % see which ones fit exactly % this is where i got into trouble, the original idea was to make % it like the fuzzy search below but i don't understand how i can % express 'when there are no more movies which make an exact fit, % and the sum is smaller then the dvdsize the list is ok too'. fitexact(Movies) :- dvdsize(Size), fitexact(Size, 0, [], Movies). % Stop when there's a perfect fit % so here i tried Size,Sum and Sum<Size in the body. That obviously % doesn't work since it instantly matches. fitexact(Size, Size, Movies, Movies). % since otherwise the same movies show up on different dvd's i % thought it would be best to delete them after they fitted. % if I don't want to do that, what's the best way to make sure once % a movie is processed it won't show up again? Should it have an extra % flag like processed(movie(name,size,processed) or should i assert % done dvd's and see if they're already in them? I wonder how long this % all would take since it's already quite slow as is. %% :- %% forall(member(Movie,Movies), retract(movie(Movie,_))). %%, !. % Otherwise keep filling fitexact(Size, Sum, Acc, Movies) :- movie(Movie, MovieSize), \+ member(Movie, Acc), % no doubles! NewSum is Sum + MovieSize, NewSum =< Size, fitexact(Size, NewSum, [Movie|Acc], Movies). removedvd(DVD) :- forall(member(Movie,DVD),retract(movie(Movie,_))). % do a fuzzy fit, try exact fits with decreasing size when % there are no exact fits. fitfuzzy(DVD) :- dvdsize(Size), fitfuzzy(DVD,Size,0). fitfuzzy(_,Size,Size) :- movies_size(Size), !. fitfuzzy(_,Size,Size) :- dvdsize(Size), !. fitfuzzy(DVD,Size,Wasted) :- CheckSize is Size - Wasted, % this feels like a horrible way to do this. I very much like suggestions % about how to make it recursive or better in general. ( fitexact(CheckSize, 0, [], DVD) -> removedvd(DVD) ; NewWasted is Wasted + 1, write('fitfuzzy: Increasing wasted space to '), write(NewWasted), nl, fitfuzzy(DVD,Size,NewWasted) ). status :- movies_count(MoviesLeft), movies_size(MoviesSize), write('Movies left: '), write(MoviesLeft), nl, write('Size left : '), write(MoviesSize), nl. burnloop :- movies_count(C), C>0, fitfuzzy(DVD), status, write('DVD = '), print(DVD),nl, nl, burnloop. % movies.db contains a list of movie(Name,Size). statements. It also % must have :- dynamic(movie/2). on top for retract to work. go :- ['movies.db'], burnloop.