// Verilog encoding of two-player escape games in a grid under time delays
module main(kid, controllable_robot, err);

	// I/O declaration
	input [1:0] kid;  // 00: U, 01: D, 10: L, 11: R
	input [3:0] controllable_robot;  // 0000: RU, 0001: UR, 0010: LU, 0011: UL, 0100: RD, 0101: DR, 0110: LD, 0111: DL, 1000: \epsilon
	output err;

	// who's turn to take a move, 1: robot, 0: kid
	reg turn;

	// coordinates declaration, r: robot, k: kid, x ranges in 0~eB, y ranges in 0~nB.
	reg [1:0] xr;
	reg [1:0] yr;
	reg [1:0] xk;
	reg [1:0] yk;

	// indicators for illegal moves, 1: illegal, 0: legal
	reg illegal_r;
	reg illegal_k;

	// intermediate memory to capture unsafe scenarios
	reg temperr;

	// time delay, tail of the queue, m for filling memory, i for loop indexing 
	parameter delay = 1;
	parameter tail = (delay+1)/2-1;
	reg [$clog2(tail+2)-1:0] m;
	integer i;
	
	// queue for memorizing actions of the robot
	reg [3:0] mem[0:tail];

	// constants declaration, eB: east bound, nB: north bound, o1: obstacle 1, o2: obstacle 2
	parameter eB = 3;
	parameter nB = 3;
	parameter xo1 = 1;
	parameter yo1 = 2;
	parameter xo2 = 3;
	parameter yo2 = 0;

	// unsafe scenarios, temperr is used to avoid boolean RHS in continuous assignment
	assign err = (temperr == 1);

	// initialization, robot: bottom-left, kid: top-right, robot moves first
	initial	begin
		temperr = 0;

		illegal_r = 0;
		illegal_k = 0;
	
		turn = 1;

		xr = 0;
		yr = 0;
		xk = eB;
		yk = nB;

		m = 0;

		// initializing the queue
		for(i=0; i<=tail; i=i+1) begin
			mem[i] = 4'b0000;
		end
	end

	// clock signal
	always @($global_clock)

	// moves
	begin
		// the robot guess actions even before playing
    	if(m <= tail) begin
    		mem[m] = controllable_robot;
    		m = m+1;
    	end
    	else begin
    		if(turn) begin  // robot moves
    			case(mem[0])
    				// RU
    				0: if(!(xr+1==xk && yr==yk || xr+1==xo1 && yr==yo1 || xr+1==xo2 && yr==yo2 || xr>=eB || yr>=nB))  // avoid running through the kid, obstacles, or walls
    				     begin
    				        xr = xr + 1;
                            yr = yr + 1;
    				     end
    				   else
    				     illegal_r = 1;
    				// UR
    				1: if(!(xr==xk && yr+1==yk || xr==xo1 && yr+1==yo1 || xr==xo2 && yr+1==yo2 || xr>=eB || yr>=nB))
    				     begin
    				        xr = xr + 1;
                            yr = yr + 1;
    				     end
    				   else
    				     illegal_r = 1;
    				// LU
    				2: if(!(xr-1==xk && yr==yk || xr-1==xo1 && yr==yo1 || xr-1==xo2 && yr==yo2 || xr<=0 || yr>=nB))
    				     begin
    				        xr = xr - 1;
                            yr = yr + 1;
    				     end
    				   else
    				     illegal_r = 1;
    				// UL
    				3: if(!(xr==xk && yr+1==yk || xr==xo1 && yr+1==yo1 || xr==xo2 && yr+1==yo2 || xr<=0 || yr>=nB))
    				     begin
    				        xr = xr - 1;
                            yr = yr + 1;
    				     end
    				   else
    				     illegal_r = 1;
    				// RD
    				4: if(!(xr+1==xk && yr==yk || xr+1==xo1 && yr==yo1 || xr+1==xo2 && yr==yo2 || xr>=eB || yr<=0))
    				     begin
    				        xr = xr + 1;
                            yr = yr - 1;
    				     end
    				   else
    				     illegal_r = 1;
    				// DR
    				5: if(!(xr==xk && yr-1==yk || xr==xo1 && yr-1==yo1 || xr==xo2 && yr-1==yo2 || xr>=eB || yr<=0))
    				     begin
    				        xr = xr + 1;
                            yr = yr - 1;
    				     end
    				   else
    				     illegal_r = 1;
    				// LD
    				6: if(!(xr-1==xk && yr==yk || xr-1==xo1 && yr==yo1 || xr-1==xo2 && yr==yo2 || xr<=0 || yr<=0))
    				     begin
    				        xr = xr - 1;
                            yr = yr - 1;
    				     end
    				   else
    				     illegal_r = 1;
    				// DL
    				7: if(!(xr==xk && yr-1==yk || xr==xo1 && yr-1==yo1 || xr==xo2 && yr-1==yo2 || xr<=0 || yr<=0))
    				     begin
    				        xr = xr - 1;
                            yr = yr - 1;
    				     end
    				   else
    				     illegal_r = 1;
    				// \epsilon
    				8: begin
    				     xr = xr;
                         yr = yr;
    				   end
    				default: illegal_r = 1;  // no possible legal moves for the robot, lose
    			endcase

				// shifting the queue
    			for(i=0; i<tail; i=i+1) begin
    				mem[i] = mem[i+1];
    			end
    
				// storing the current action which takes effect in the future
    			mem[tail] = controllable_robot;	

            end
            
    		else begin  // kid moves
				case(kid)
					// D
					1: if(!(xk==xo1 && yk-1==yo1 || xk==xo2 && yk-1==yo2 || yk<=0))
                         yk = yk - 1;
				       else
				         illegal_k = 1;
					// L
					2: if(!(xk-1==xo1 && yk==yo1 || xk-1==xo2 && yk==yo2 || xk<=0))
                         xk = xk - 1;
				       else
				         illegal_k = 1;
					default: illegal_k = 1;
				endcase
			end
    
    		begin
    			// flipping the turn of taking moves
    			turn = ~turn;	
    
    			// enable temperr in case of unsafe scenarios
    			if(!illegal_k && (  // legal_k moves
    				xr == xo1 && yr == yo1 ||  // collision with obstacle 1
    				xr == xo2 && yr == yo2 ||  // collision with obstacle 2
    				xr == xk && yr == yk ||  // caught by the kid
    				illegal_r  // illegal_r moves
      				))
    				temperr = 1;
    			else
    				temperr = 0;
    		end
        end

	end

endmodule
