Prolog: connect4 check diagonal end - list

The grid is a list of 7 lists, each list is a column that can contains 6 elements maximum. For victory check, I implemented vertical victory and horizontal victory as below. But I have problems with diagonal check. Any suggestions?
% Vertical end check
isEndVert(Grid, J, N) :-
getColumn(N, Grid, Column),
sublist([J,J,J,J], Column),
!.
isEndVert(Grid, J, N) :-
N > 0,
N1 is N-1,
isEndVert(Grid, J, N1).
% Horizontal end check
isEndHor(Grid, J, N) :-
getLine(N, Grid, Line),
sublist([J,J,J,J], Line),
!.
isEndHor(Grid, J, N) :-
N > 0,
N1 is N-1,
isEndHor(Grid, J, N1).

Well, you have getLine/3 and getColumn/3, let's make getDiagonal/3:
getDiagonal(Grid, Diagonal) :-
length(Grid, Columns),
bagof(Cell,
I^Row^(between(1, Columns, I),
(nth1(I, Grid, Row),
nth1(I, Row, Cell))),
Diagonal).
This gets us the "Ith" elements of the list for each list numbered from I. This gets us basically the descending diagonal. We need another clause to get the other:
getDiagonal(Grid, Diagonal) :-
length(Grid, Columns),
bagof(Cell,
OppositeI^I^Row^(between(1, Columns, I),
(OppositeI is Columns + 1 - I,
nth1(I, Grid, Row),
nth1(OppositeI, Row, Cell))),
Diagonal).
The ^ syntax in here is a quantifier; it basically says to bagof/3 that we don't consider different instantiations of those variables as necessitating new bags. findall/3 is more concise but I have a strange preference for bagof/3.
Having built that you can probably solve the problem the way you do for the vertical and horizontal cases.

using only list scan, an example of 2 wins, matching forward and backward diagonals:
test(J) :- Grid=[
[-,-,-,-,-,-,-],
[-,-,-,-,-,-,-],
[-,-,-,J,-,-,-],
[-,-,J,-,J,-,-],
[-,J,-,-,-,J,-],
[J,-,-,-,-,-,J]
], append(_,[A,B,C,D|_],Grid), % test 4 consecutive rows
( start([A,B,C,D],J) ; start([D,C,B,A],J) ).
% on first row of 4, find first matching column
start([[J|_]|R],J) :- skip1(R,S), diag(S,J). % first found, match diag
start(R,J) :- skip1(R,S), start(S,J).
% each first cell of rows' sequence must match
diag([[J|_]],J). % last row: success
diag([[J|_]|T],J) :- skip1(T,S), diag(S,J).
% discard first column of each row
skip1([],[]).
skip1([[_|R]|T],[R|S]) :- skip1(T,S).
I think it should work independently of the matrix representation being rows or columns oriented. Comments assume a row oriented representation.

Related

How to get prime numbers from list and put them in empty list

I want to get all prime numbers from a list of numbers and put it into another empty list.
My problem is that whenever the function isPrime is false, the program is terminated.
I'm very beginner in prolog, so if you have any feedback I'll appreciate the help.
Here is my code below:
check_prime(X):-
Xtemp is integer(X/2),
isPrime(X,Xtemp).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
isPrime(_,2).
isPrime(2,_).
isPrime(Num,Counter):-
X is Counter-1,
X \= 0,
X2 is mod(Num,X),
X2 \= 0,
isPrime(Num,X).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prime_list([],Y).
prime_list([H|T],[H|T2]):-
check_prime(H),
prime_list(T,T2).
Your check_prime function will give true even for non-prime numbers.
Example: check_prime(4) will call isPrime(4, 2), which will unify with the first clause of isPrime.
An example of code that gives you the list of primes would be this:
% predicate to check if X has any divisors
divisible(X,Y) :- 0 is X mod Y, !.
divisible(X,Y) :- X > Y+1, divisible(X, Y+1).
%predicate to check if that number is prime by using the divisible predicate
isPrime(2) :- true,!.
isPrime(X) :- X < 2,!,false.
isPrime(X) :- not(divisible(X, 2)).
%predicate that returns the resulted list
primeList([], []). % stopping condition, when list empty
% we add current element to the resulting list if it is prime
primeList([H|T], [H|R]):- isPrime(H), !, primeList(T, R).
% otherwise, we just skip it
primeList([_|T], R):- primeList(T, R).
Query: ?-primeList([1,2,3,4,5,6,7,8,9], R). => R=[2,3,5,7]

Give as a solution every different number in a list of lists

I need to do a predicate, select(ListOfLists, X) that returns as a solution every different number in a list of lists, starting with the numbers that are alone in a list, for example:
select([[1,2,3],[1,2],[4],[3]],X).
Would return:
X = 4 ;
X = 3 ;
X = 2 ;
X = 1
Order doesn't matter as long as the numbers that are alone in the list are shown first.
To do this, first I coded 2 other predicates, which are:
%OrderedList is Lists ordered by size.
orderListsBySize(Lists, OrderedLists).
Example: orderListsBySize([[1,2],[6],[3,4,5]], L). ->L = [[6], [1,2], [3,4,5]]
And
%ListsWithoutX is Lists without the X elements
removeFromLists(X, Lists, ListsWithoutX).
Example: removeFromLists(1,[[1,2],[3],[4,1,5]],L). -> L = [[2],[3],[4,5]]
Both predicates work.
Then, to do the select(ListOfLists, X) predicate, I tried the following:
select([[X|[]]|_], X). select(L1,S) :-
orderListsBySize(L1, [[X|XS]|LS]),
length(XS, A),
A == 0,
select([[X|[]]|M], S),
removeFromLists(X, [XS|LS], M).
select([[X|_]|_], X).
But it doesn't work.
It's not a hard exercise to do in other languages, the problem is that it's still hard for me to understand how prolog works. I appreaciate any help, thanks!
You could start with:
select2(ListOfLists,Element):-
length(List,_Len),
member(List,ListOfLists),
member(Element,List).
Which will return all the answers, but then get stuck in a loop looking for ever bigger lists.
This can be averted using the :-use_module(library(clpfd)). and defining a fd_length/2 which wont keep looking for bigger lists then exist in the list of lists.
fd_length(L, N) :-
N #>= 0,
fd_length(L, N, 0).
fd_length([], N, N0) :-
N #= N0.
fd_length([_|L], N, N0) :-
N1 is N0+1,
N #>= N1,
fd_length(L, N, N1).
select(ListOfLists,Element):-
maplist(length,ListOfLists,Lengths),
sort(Lengths,SortedLength),
last(SortedLength,Biggest),
Biggest #>= Len,
fd_length(List,Len),
member(List,ListOfLists),
member(Element,List).
Example Query:
?-select([[1,2,3],[1,2],[4],[3]],X).
X = 4
X = 3
X = 1
X = 2
X = 1
X = 2
X = 3
false
If you want unique solutions, you could enclose in a setof/3 and then call member/2 again.

Number of ways to tile a 2xN grid with forbidden positions with 2x1 and 1x2 dominoes?

I was keen to know the algorithm to solve this problem. The formal description of the problem statement is something like this-Given N(<100) and dominoes 2x1 and 1x2 I have to find the number of different grid tilings possible. The difference here is that some cells will be blackened to denote the forbidden position.
Input:
5
01000
00010
Output:
1
The 0 in the input represents an empty cell and 1 forbidden cell.
I found a similar question here Hexagonal Grid Tiling . Although there was a slight mention about solving these kinds of problem with Dynamic Programming with Bitmasks, I was unable to find any thorough explanation regarding this technique.
PS: Although I know how to solve a general grid tiling problem, say in this problem only if we are given only the empty cells then a recurrence can be formed as F(n) = F(n-1) + F(n-2), by either placing a 1x2 domino or placing two 2x1 dominoes to cover first and first two columns respectively. This can be solved iteratively or even for Large N(say > 10^7) we can use Matrix Exponentiation technique. But I am interested in knowing about the technique of solving these kinds of problems by DP+Bitmasks. Any help would be appreciated.
For i = n, n-1, ..., 1 you calculate f00 (i) = "Number of combinations to fill from column i if column i contained 0,0", f01 (i) = "Number of combinations to fill from column i if column i contained 0,1", f10 (i) = "Number of combinations to fill from column i if column i contained 1,0", f11 (i) = "Number of combinations to fill from column i if column i contained 1,1"
Obviously f00 (n) = f11 (n) = 1, f01 (n) = f10 (n) = 0.
f00 (i) if i < n: You can use one vertical tile whatever is in the next column, or two horizontal tiles if the next column is (0, 0). So if the next column is (0, 0) then the result is f00 (i + 1) + f11 (i + 1); if the next column is (0, 1), (1, 0) or (1, 1) then f00 (i) = f01, f10 or f11 (i + 1).
f10 (i) for i < n: You must use one horizontal tile. If the next column contains (0, 1) or (1, 1) then the result is 0; if the next column contains (0, 0) or (1, 0) then the result is f01 (i+1) or f11 (i+1).
f01 (i) works the same.
f11 (i) = f00, f01, f10 or f11 (i + 1) depending what's in the next column.
Solution is easily found in linear time.

How can i find pairs in a list, Prolog?

I have a problem,
I have a list with numeric elements such as in the example.
I´d like to find all pairs, and count it. (Every Element can only be one part of one pair)
?- num_pairs([4,1,1,1,4],N).
N=1;
Can anyone help me to solve this problem??
You need several things to make it work:
An ability to count the number an item is repeated in a list
An ability to remove all elements matching a value from the list
An ability to conditionally increment a number
Here is how you can count:
count([], _, 0).
count([H|T], H, R) :- count(T, H, RT), R is RT + 1.
count([H|T], X, R) :- H \= X, count(T, X, R).
Deletion can be done with SWI's delete/3 predicate; this is a built predicate.
Adding one conditionally requires two rules - one when the count equals one, and another one for when the count does not equal one.
add_if_count_is_one(H, T, RT, R) :- count(T, H, 1), R is RT + 1.
add_if_count_is_one(H, T, R, R) :- count(T, H, X), X \= 1.
Finally, counting pairs could look like this:
num_pairs([], 0).
num_pairs([H|T], R) :- delete(T, H, TT),
num_pairs(TT, RT),
add_if_count_is_one(H, T, RT, R).
An empty list has no pairs; when an item is counted as part of a pair, its copies are removed from the rest of the list.
Here is this running program on ideone.

Select K random lines from a text file

This is an extension of the original question of selecting a random line from a text of X lines where the probability of the text line selected is 1/X. The trick is to select the Jth line if you query a random variable Y with a range of [0,1) and it returns a value less than 1/J.
Now in this new version of the problem we have to select K random lines where K is less than X. I believe the probability for each line should be K/X.
I'm stuck on how to extend the original solution to K lines. Is it possible? any explanations would be great.
This can be solved using a generalization of the original algorithm. The intuition is as follows: maintain a list of k candidate lines from the file, which are initially seeded to the first k lines. Then, from that point forward, upon seeing the nth line of the file:
Choose a random value x between 1 and n, inclusive.
If x > k, ignore this element.
Otherwise, replace element x with the nth line of the file.
The proof that this correctly samples each element with probability k / n, where n is the total number of lines in the file, is as follows. Assume that n ≥ k. We prove by induction that each element has probability k / n of being picked by showing that after seeing z elements, each of those elements has probability k / z of being chosen. In particular, this means that after seeing n elements, each has probability k / n as required.
As our inductive basis, if we see exactly k elements, then each is picked. Thus the probability of being chosen is k / k, as required.
For the inductive step, assume that for some z ≥ k, each of the first z elements have been chosen with probability k / z and consider the (z + 1)st element. We choose a random natural number in the range [1, z + 1]. With probability k / (z + 1), we decide to choose this element, then evict some old element. This means that the new element is chosen with probability k / (z + 1). For each of the z original elements, the probability that it is chosen at this point is then the probability that we had chosen it after the first z elements were inspected (probability k / z, by our inductive hypothesis), and the probability that we retain it is z / (z + 1), since we replace it with probability 1 / (z + 1). Thus the new probability that it is chosen is (k / z) (z / (z + 1)) = k / (z + 1). Thus all of the first z + 1 elements are chosen with probability k / (z + 1), completing the induction.
Moreover, this algorithm runs in O(n) time and uses only O(k) space, meaning that the runtime is independent of the value of k. To see this, note that each iteration does O(1) work, and there are a total of O(n) interations.
If you're curious, I have an implementation of this algorithm as a C++ STL-style algorithm available here on my personal site.
Hope this helps!
First select the first element randomly out of the X lines using the first algorithm. Then select the second out of the remaining X-1 lines. Run this process K times.
The probability of any given set of K lines is (X choose K). I'll leave it up to you to verify that this algorithm gives the desired uniform distribution.