import random
import copy
import math

__author__ = 'sondredyvik, paulpm'


class State:
    def __init__(self, board, score):
        self.board = board
        self.score = score


class Board(object):
    def __init__(self):
        self.board = [[0 for _ in range(4)] for _ in range(4)]
        self.free_tiles = []
        self.full = False
        self.score = 0
        self.state = State(self.board, self.score)

    def get_free_cells(self, state):
        free_tuples = []
        for x in range(4):
            for y in range(4):
                if state.board[x][y] == 0:
                    free_tuples.append((x, y))
        return free_tuples

    def place_tile(self, state):
        choices = [2, 2, 2, 2, 2, 2, 2, 2, 4]
        value = random.choice(choices)
        free_slots = self.get_free_cells(state)
        if free_slots:
            x, y = random.choice(free_slots)
            state.board[x][y] = value
        else:
            self.full = True

    def count_vertical_moves(self,state):
        count =0
        for y in reversed(range(4)):
            for x in reversed(range(4)):
                if state.board[x][y] != 0:
                    for z in range(x, -1, -1):
                        if state.board[z][y] != 0 and x != z:
                            if state.board[x][y] == state.board[z][y]:
                                count += 1
                                break
                            if state.board[z][y] != 0 and state.board[z][y] != state.board[x][y]:
                                break
        return math.ceil(count/2)

    def count_horizontal_moves(self, state):
        count = 0

        for x in range(4):
            for y in range(4):
                if state.board[x][y] != 0:
                    for z in range(y, 4):
                        if state.board[x][y] == state.board[x][z] and y != z:
                            count += 1

                        if state.board[x][z] != 0 and state.board[x][z] != state.board[x][y]:
                            break

        return math.floor(count/2)

    def move_all_tiles_right(self, state):
        moved = False
        for x in reversed(range(4)):
            for y in reversed(range(4)):
                if state.board[x][y] != 0:
                    for z in range(y, -1, -1):
                        if state.board[x][y] == state.board[x][z] and y != z:
                            state.board[x][y] += state.board[x][z]
                            state.board[x][z] = 0
                            state.score += state.board[x][y]
                            moved = True
                            break
                        if state.board[x][z] != 0 and state.board[x][z] != state.board[x][y]:
                            break

        for x in reversed(range(4)):
            for y in reversed(range(4)):
                if state.board[x][y] == 0:
                    for z in range(y, -1, -1):
                        if state.board[x][z] != 0:
                            state.board[x][y] = state.board[x][z]
                            state.board[x][z] = 0
                            moved = True
                            break
        return moved

    def move_all_tiles_left(self, state):
        moved = False
        for x in range(4):
            for y in range(4):
                if state.board[x][y] != 0:
                    for z in range(y, 4):
                        if state.board[x][y] == state.board[x][z] and y != z:
                            state.board[x][y] += state.board[x][z]
                            state.board[x][z] = 0
                            state.score += state.board[x][y]
                            moved = True
                            break
                        if state.board[x][z] != 0 and state.board[x][z] != state.board[x][y]:
                            break

        for x in range(4):
            for y in range(4):
                if state.board[x][y] == 0:
                    for z in range(y, 4):
                        if state.board[x][z] != 0:
                            state.board[x][y] = state.board[x][z]
                            state.board[x][z] = 0
                            moved = True
                            break
        return moved

    def has_available_moves(self):
        # We only need one
        copyboard = copy.deepcopy(self.state)

        return self.move("up", copyboard) \
               or self.move("down", copyboard) \
               or self.move("left", copyboard) \