////////////////////////////////////////////////////////////////////
// Game of Life Boolean POMDP
//
// A simple DBN to encode Conway's cellular automata "game of life" 
// on a grid.  One gets a reward for generating patterns that keep 
// the most cells alive.
//
// Author: Scott Sanner (ssanner [at] gmail.com)
////////////////////////////////////////////////////////////////////
domain game_of_life_mdp {
  	
	requirements = { reward-deterministic };

	types { 
		x_pos : object;
		y_pos : object; 
	};
      	
	pvariables { 
		NOISE-PROB(x_pos,y_pos) : { non-fluent, real, default = 0.1 };
		NEIGHBOR(x_pos,y_pos,x_pos,y_pos) : { non-fluent, bool, default = false };
		alive(x_pos,y_pos) : { state-fluent,  bool, default = false };
		set(x_pos,y_pos)   : { action-fluent, bool, default = false };
	};
  
	cpfs {
		// Conway's game of life rules (from Wikipedia):
		// 1. Any live cell with fewer than two live neighbors dies, as if caused by under-population.
   		// 2. Any live cell with more than three live neighbors dies, as if by overcrowding.
   		// 3. Any live cell with two or three live neighbors lives on to the next generation.
   		// 4. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
   		//
   		// For interactivity: we allow an agent to explicitly set different cells.
		
		alive'(?x,?y) = 
			if ([alive(?x,?y) ^ ([sum_{?x2 : x_pos, ?y2 : y_pos} NEIGHBOR(?x,?y,?x2,?y2) ^ alive(?x2,?y2)] >= 2) 
							^ ([sum_{?x2 : x_pos, ?y2 : y_pos} NEIGHBOR(?x,?y,?x2,?y2) ^ alive(?x2,?y2)] <= 3)]
						| [~alive(?x,?y) ^ ([sum_{?x2 : x_pos, ?y2 : y_pos} NEIGHBOR(?x,?y,?x2,?y2) ^ alive(?x2,?y2)] == 3)]
						| set(?x,?y))
			then Bernoulli(1.0 - NOISE-PROB(?x,?y))
			else Bernoulli(NOISE-PROB(?x,?y));
	};
    	
	reward = sum_{?x : x_pos, ?y : y_pos} [alive(?x,?y) - set(?x,?y)];
    	
    state-action-constraints {
    	forall_{?x : x_pos, ?y : y_pos}
    		[(NOISE-PROB(?x,?y) >= 0.0) ^ (NOISE-PROB(?x,?y) <= 1.0)];
    };
}
