
#pragma once

#include "../lib/assert2.h"
#include "../lib/move.h"

#include "policy.h"


namespace Morat {

template<class Board>
class InstantWin : public Policy<Board> {
	int max_rollout_moves;
	int cur_rollout_moves;

	Move saved_loss;
public:

	InstantWin() : max_rollout_moves(10), cur_rollout_moves(0), saved_loss(M_UNKNOWN) {
	}

	void rollout_start(Board & board, int max) {
		if(max < 0)
			max *= - board.lines();
		max_rollout_moves = max;

		cur_rollout_moves = 0;
		saved_loss = M_UNKNOWN;
	}

	Move choose_move(const Board & board, const Move & prev) {
		if(saved_loss != M_UNKNOWN)
			return saved_loss;

		if(cur_rollout_moves++ >= max_rollout_moves)
			return M_UNKNOWN;

		//must have an edge connection, or it has nothing to offer a group towards a win
		const auto * c = board.cell(prev);
		if(c->numedges() == 0)
			return M_UNKNOWN;

		MoveValid start, cur, loss = M_UNKNOWN;
		Side turn = ~board.to_play();

		//find the first empty cell
		int dir = -1;
		const MoveValid* neighbors = board.neighbors(prev);
		for(int i = 0; i < 6; i++){
			start = neighbors[i];

			if(!board.on_board(start) || board.get(start) != turn){
				dir = (i + 5) % 6;
				break;
			}
		}

		if(dir == -1) //possible if it's in the middle of a ring
			return M_UNKNOWN;

		cur = start;

//		logerr(board.to_s(true));
//		logerr(prev.to_s() + ":");

		//follow contour of the current group looking for wins
		do{
//			logerr(" " + cur.to_s());
			//check the current cell
			if(board.on_board(cur) && board.get(cur) == Side::NONE && board.test_outcome(cur, turn) == +turn){
//				logerr(" loss");
				if(loss == M_UNKNOWN){
					loss = cur;
				}else if(loss != cur){
					saved_loss = loss;
					return cur; //game over, two wins found for opponent
				}
			}

			//advance to the next cell
			const MoveValid* neighbors = board.neighbors(cur);
			for(int i = 5; i <= 9; i++){
				int nd = (dir + i) % 6;
				MoveValid next = neighbors[nd];

				if(!board.on_board(next) || board.get(next) != turn){
					cur = next;
					dir = nd;
					break;
				}
			}
		}while(cur != start); //potentially skips part of it when the start is in a pocket, rare bug

//		logerr("\n");

		return loss; // usually M_UNKNOWN
	}
};

}; // namespace Morat
