:-dynamic(fired/1).
:-dynamic(stopped/0).
:-dynamic(current_list/1).

go:-
  retractall(current_list(_)),
  retractall(stopped),
  assert(current_list([5,3,2,4,1])),
  current_list(X),
  write('Initial state:  '), write(X), nl,
  run_rules.

run_rules:-
  \+(stopped),!,
  conflict_set(CList),
  choose_rule(CList,Rule),
  fire_rule(Rule),
  run_rules.

run_rules.

conflict_set(CList):-
  findall(R, belongs_to_c_set(R), CList).

belongs_to_c_set(rule(N, Cond, Act)):-
  rule(N, Cond, Act),
  satisfy(Cond).

fire_rule(rule(N, Cond, Act)):-
  call(Act),!.

choose_rule([R|Ignore], R).

rule(1,[left_of(A,B),left_of(B,C),bigger_than(A,C)], swap(A,C)).
rule(2,[left_of(A,B),bigger_than(A,B)], swap(A,B)).
rule(3,[no_left_of_and_bigger],stop).

satisfy(Conditions):-
  satisfy_each(Conditions),!.

satisfy_each([]).
satisfy_each([H|T]):-
  call(H), satisfy_each(T).

left_of(A,B):-
  current_list(L),
  split(L,A,[B|_]).

bigger_than(A,B):-
  A>B.

no_left_of_and_bigger:-
  \+(some_left_of_and_bigger).

some_left_of_and_bigger:-
  left_of(A,B),
  bigger_than(A,B).

swap(A,B):-
  retract(current_list(L)),
  list_with_swap(L,A,B,New),
  assert(current_list(New)),
  write('Swap performed: '),
  write(New),nl.

stop:-
  assert(stopped).

list_with_swap([],_,_,[]).

list_with_swap([A|T],A,B,[B|T1]):-
  list_with_swap(T,A,B,T1).

list_with_swap([B|T],A,B,[A|T1]):-
  list_with_swap(T,A,B,T1).

list_with_swap([H|T],A,B,[H|T1]):-
  \+(H=A),\+(H=B),
  list_with_swap(T,A,B,T1).

split([H|T],H,T).

split([H|T],A,List):-
  split(T,A,List).
