'Prolog, check for specific list parameter

% adds two lists together
add_pairs(X, [], X).
add_pairs([I1, I2, I3, I4, I5], [I7, I8, I9, I10, I11], [O1, O2, O3, O4, O5]) :-
  O1 is I1 + I7,
  O2 is I2 + I8,
  O3 is I3 + I9,
  O4 is I4 + I10,
  O5 is I5 + I11.

% Checks to see if the meal is satisfactory
check_sat([_, E2, E3, E4, E5], Len) :-
  E2 >= 3,
  E3 =< Len - 3,
  E4 =< Len - 3,
  E5 >= 3.

% Adds all lists in L together.
add_lists([L|[]], L).
add_lists([X, Y|T], Out) :-
  add_pairs(X, Y, Sum),
  append([Sum], T, TOut),
  add_lists(TOut, Out).

% Calls to the functions, determining if a meal is satisfactory
satisfactory_meal(L) :-
  add_lists(L, Output),
  length(L, Len),
  check_sat(Output, Len).

So, I'm currently working on a program where I'm given some data as input. It returns true if certain conditions are met and false otherwise. Basically, the list represents the attributes of a meal.

[Dish_number, Organic, Has_dairy, Has_meat, Locally_sourced]

The dish number is any number and the following attributes are represented as present if 1 is found and absent if 0 is in its place.

For example:

satisfactory_meal([
     [8,  0, 0, 0, 1],
     [9,  1, 1, 0, 1],
     [23, 1, 0, 0, 1],
     [2,  1, 0, 1, 0],
     [6,  0, 0, 1, 1]
]).

Returns true. Because I need 3 or more instances of Organic and Locally_sourced. And there are less than or equal to the length of the List - 3 of Meat or Dairy.

satisfactory_meal([
     [4,  1, 0, 0, 0],
     [7,  0, 1, 0, 1],
     [90, 0, 0, 0, 0],
     [3,  0, 0, 1, 1]
]).

returns false because organic has a single instance and locally_sourced has two. Less than what's needed.

All's good and well with my current program setup... However, there's a test case I cannot return properly. The program should return false if a single meal is disliked by all.

Which looks like this:

% No one can eat dish 3 
satisfactory_meal([
     [1, 1, 0, 0, 1],
     [3, 0, 1, 1, 1],
     [5, 0, 0, 0, 1],
     [7, 1, 0, 1, 0],
     [9, 1, 0, 0, 1]
]).
% No one can eat dish 9
satisfactory_meal([
     [1, 1, 0, 0, 0],
     [3, 1, 0, 0, 1],
     [5, 0, 0, 0, 1],
     [7, 1, 0, 0, 1],
     [9, 0, 1, 1, 1]
]).

A meal is disliked by all if the list looks like [#, 0, 1, 1, 0] or [#, 0, 1, 1, 1].

My issue is with how I'm currently handling my lists. I'm adding them all together, making it very easy to look for less than, greater than, and equal to values. I can't arithmetically figure out how to find the instance where a dish is disliked by all. AKA [#, 0, 1, 1, 0] or [#, 0, 1, 1, 1]. Is there a way to figure it out after summing the lists together? Or do I have to create a new function and look for those instances before adding the lists together? Any help would be most appreciated as I'm close to making this program work! Thank you.



Solution 1:[1]

I figured it out. I looked through the data before adding it together, creating a function that looks for the lack of instances of [#, 0, 1, 1, 0] or [#, 0, 1, 1, 1].

nonmember(Arg,[Arg|_]) :-
    !,
        fail.
nonmember(Arg,[_|Tail]) :-
        !,
        nonmember(Arg,Tail).
nonmember(_,[]).

  nonmember([_,0,1,1,0], L),
  nonmember([_,0,1,1,1], L),

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Swainstein