This problem was fun because it involved some real parsing. Being able to treat strings directly as Prolog atoms with
term_string/2 was a neat way to deconstruct the first column in the solution (e.g.
1-3) directly into a pair.
Before coming to use
include/3, I tried out
maplist/3 with some moderate success by adding an extra variable to
verify. For some reason, the interpreter was unhappy with it.
include/3 is a much nicer way to define the list anyhow. I was also surprised that I had to write my own predicate to count the number of times a particular item exists within a list. I might have been able to get away with this using
include/3, but I’m not proficient enough yet to know.
% https://stackoverflow.com/a/46902736 count(_, , 0). count(C, [C|T], N):- count(C, T, Res), N is Res+1. count(C, [X|T], N):- C \= X, count(C, T, N). parse(String, Data):- split_string(String, '\s', '\s', [MinMax, CharColon, Password]), term_string(Min-Max, MinMax), % remove the colon in the data string_chars(CharColon, [Char|_]), Data = (Min, Max, Char, Password). verify(String):- parse(String, (Min, Max, Char, Password)), string_chars(Password, Chars), count(Char, Chars, N), N >= Min, N =< Max. main(String, Result):- split_string(String, '\n', '\n', L), include(verify, L, Verified), length(Verified, Result). verify2(String):- parse(String, (Min, Max, Char, Password)), string_chars(Password, Chars), nth1(Min, Chars, Pos0), nth1(Max, Chars, Pos1), Pos0 \= Pos1, ( Pos0 = Char, Pos1 \= Char; Pos0 \= Char, Pos1 = Char). main2(String, Result):- split_string(String, '\n', '\n', L), include(verify2, L, Verified), length(Verified, Result). sample(X):- X = "1-3 a: abcde 1-3 b: cdefg 2-9 c: ccccccccc".