Two friends P1 and P2 send the SAME message M to a mutual friend say P3.
However due to some network damage P3 only receives only one character at a time without knowing if the character received belongs to P1 or P2.
Furthermore P3 might receive X characters from P1 then Y characters from P2 or vice versa but whatever the order P3 will receive ALL characters that both P1 and P2 sent.
Given the sequence S of characters that P3 received help him determine the initial message M that consists only of 0s and 1s
Note that there might be more than one solutions to the problem however getting just one is fine.
Examples :
1) S = [0,1,0,0,1,0] then M = "010"
2) S = [0,0,1,1,0,0,1,1,0,0] then M = "01010" or M = "00110"
To clarify the order and the ownership of each character :
Say M = "cat" then S might be :
1) [c1,c2,a2,t2,a1,t1]
2) [c1,a1,t1,c2,a2,t2]
3) [c1,c2,a1,a2,t2,t1]
Where xi stands for : Character x belongs to person i.
Given the fact that P1 and P2 send the same message then :
- There is a fixed amount of 0s that P1 and P2 can send
- There is also a fixed amount of 1s that P1 and P2 can send
- Length of M will obviously be an even number
At first I implemented the predicate above using Prolog and A's (0) and B's (1) where backtracking is fairly easy and I applied a constraint that prunes my search tree so that my approach is not a brute force one :
Prolog Code :
countCharacters([],A,B,A,B).
countCharacters([C|T],A,B,X,Y) :- % Count A's per person and B's per person
(C == a -> A1 is A + 1,countCharacters(T,A1,B,X,Y);
B1 is B + 1,countCharacters(T,A,B1,X,Y)).
countCharacters(L,A,B) :-
countCharacters(L,0,0,X,Y),
A is X / 2,
B is Y / 2.
rightOrder([],_) :- !.
rightOrder(_,[]) :- !.
rightOrder([C1|_],[C2|_]) :- C1 \= C2,!,false.
rightOrder([C|T1],[C|T2]) :- % Constraint that checks if two lists have the same order
rightOrder(T1,T2).
determine([],M1,M2,_,_,_,_,M1) :- M1 == M2,!.
determine(L,M1,M2,A1,B1,A2,B2,X) :-
A1 == 0,
B1 == 0,
append(M2,L,NM2),
rightOrder(M1,NM2),
determine([],M1,NM2,A1,B1,A2,B2,X).
determine([a|T],M1,M2,A1,B1,A2,B2,X) :-
A1 > 0,
NA1 is A1 - 1,
append(M1,[a],NM1),
determine(T,NM1,M2,NA1,B1,A2,B2,X).
determine([b|T],M1,M2,A1,B1,A2,B2,X) :-
B1 > 0,
NB1 is B1 - 1,
append(M1,[b],NM1),
determine(T,NM1,M2,A1,NB1,A2,B2,X).
determine([a|T],M1,M2,A1,B1,A2,B2,X) :-
A2 > 0,
NA2 is A2 - 1,
append(M2,[a],NM2),
rightOrder(M1,NM2),
determine(T,M1,NM2,A1,B1,NA2,B2,X).
determine([b|T],M1,M2,A1,B1,A2,B2,X) :-
B2 > 0,
NB2 is B2 - 1,
append(M2,[b],NM2),
rightOrder(M1,NM2),
determine(T,M1,NM2,A1,B1,A2,NB2,X).
determine(L,M) :-
countCharacters(L,AS,BS),
determine(L,[],[],AS,BS,AS,BS,M).
The code above is not that optimized as I've been studying Prolog for just a few weeks now, however I need some help or insight on how to implement the same predicate in Haskell as I have no clue on how to backtrack.
If you need more clarifications let me know.