#  HueFiend, by Nils Veidis, 2017
#  First independent coding project (UC Berkeley)


difficulty = {"Beginner": 4, "Easy": 5, "Medium": 8, "Hard": 10} #value=how many squares per row
valid_difficulty = False #has the user selected a valid difficulty ("Beginner", "Easy", ...)

while valid_difficulty == False:
    difficulty_selected = input("Select a difficulty: Beginner, Easy, Medium, or Hard? ")
    if difficulty_selected in difficulty:
        valid_difficulty = True
    else:
        print("Please select Beginner, Easy, Medium, or Hard.")

if valid_difficulty == True: #user chooses both corner colors w R G B values
    color1 = []
    color2 = []
    RGB = ["R", "G", "B"]
    for value in RGB:
        not_color_chosen = True
        while not_color_chosen:    
            color_selected = input("Input "+ value +" value of first color: ")
            if not color_selected.isalpha() and int(color_selected) <= 255 and int(color_selected) >= 0:
                color1.append(int(color_selected))
                not_color_chosen = False
            else: 
                print("Please insert an R G B value between 0 and 255.")
    for value in RGB:
        not_color_chosen = True
        while not_color_chosen:    
            color_selected = input("Input "+ value +" value of second color: ")
            if not color_selected.isalpha() and int(color_selected) <= 255 and int(color_selected) >= 0:
                color2.append(int(color_selected))
                not_color_chosen = False
            else: 
                print("Please insert an R G B value between 0 and 255.")

import random #for board shuffling
import copy #for ".deepcopy" function of game_winning_board

import pygame
pygame.init()

 
BLACK = (  0,   0,   0)
WHITE = (255, 255, 255)

screen_width = 800
screen_height = 800
size = [screen_width, screen_height]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("I Love Hue")

margin = 0 #thickness of borders / outline

square_width = (screen_width / difficulty[difficulty_selected])-margin
square_height = (screen_height / difficulty[difficulty_selected])-margin


grid = [] #a list of coordinates that corresponds to the grid size selected 
            #(e.g. (0,0) = upper left block, (0,1) = 1 block to the right, (1,0) = one block below)
for x in range(difficulty[difficulty_selected]):
    n = 0
    while n != difficulty[difficulty_selected]:
        grid.append([x])
        n += 1
y = 0
for lst in grid[:]:
    if y < difficulty[difficulty_selected]:
        lst.append(y)
        y += 1
    elif y >= difficulty[difficulty_selected]:
        y = 0
        lst.append(y)
        y += 1


grid_colors = [] #live grid (mutable)
game_winning_grid = [] #fixed correctly completed grid (fixed)


square_x = 0 #connects coordinate number of square to RGB value
square_y = 0
def draw_row(row_number, leftmost_color, last_color):
    global grid_colors
    global game_winning_grid
    global square_x
    global square_y
    left_color = leftmost_color[:]
    end_color = last_color[:] #FIXED END
    start_color = left_color[:] #FIXED STARTING COLOR
    for r in range(difficulty[difficulty_selected]):
        x_coord = (margin + square_width) * r + margin
        y_coord = (margin + square_height) * int(row_number) + margin
        pygame.draw.rect(screen, left_color, [x_coord, y_coord, square_width, square_height])
        grid_colors.append([left_color[0], left_color[1], left_color[2], square_x, square_y])
        left_color[0] = abs(left_color[0] - (abs(start_color[0] - end_color[0])) // (difficulty[difficulty_selected]-1))
        left_color[1] = abs(left_color[1] - (abs(start_color[1] - end_color[1])) // (difficulty[difficulty_selected]-1))
        left_color[2] = abs(left_color[2] - (abs(start_color[2] - end_color[2])) // (difficulty[difficulty_selected]-1))
        square_y += 1
    square_x += 1
    square_y = 0
    game_winning_grid = copy.deepcopy(grid_colors[:])
    pygame.display.update()


def draw_board(top_left, bottom_left, top_right, bottom_right):
    global square_x
    global square_y
    tl_color = top_left[:] #FIXED STARTING COLOR (tl = top left)
    tr_color = top_right[:] #FIXED ENDING COLOR (tr = top right)
    for x in range(difficulty[difficulty_selected]):
        draw_row(x, top_left, top_right)
        top_left[0] = top_left[0] - (abs(tl_color[0] - bottom_left[0])) // (difficulty[difficulty_selected]-1)
        top_left[1] = top_left[1] - (abs(tl_color[1] - bottom_left[1])) // (difficulty[difficulty_selected]-1)
        top_left[2] = top_left[2] - (abs(tl_color[2] - bottom_left[2])) // (difficulty[difficulty_selected]-1)
        top_right[0] = top_right[0] - (abs(tr_color[0] - bottom_right[0])) // (difficulty[difficulty_selected]-1)
        top_right[1] = top_right[1] - (abs(tr_color[1] - bottom_right[1])) // (difficulty[difficulty_selected]-1)
        top_right[2] = top_right[2] - (abs(tr_color[2] - bottom_right[2])) // (difficulty[difficulty_selected]-1)
    square_x = 0
    square_y = 0
    pygame.display.update()


def grid_to_board(): #takes in grid_color list and translates the list contents (i.e. R B G values) to new visual board
    global square_x
    global square_y
    global grid_colors
    i = 0
    for x in range(difficulty[difficulty_selected]):
        for y in range(difficulty[difficulty_selected]):
            x_coordinate = (screen_height // difficulty[difficulty_selected]) * y + margin
            y_coordinate = (screen_width // difficulty[difficulty_selected]) * x + margin
            pygame.draw.rect(screen, grid_colors[i][:3], [x_coordinate, y_coordinate, square_width, square_height])
            #print(grid_colors[i][3:]) #TO CHECK IF COORDINATE RECORDING WORKS PROPERLY
            i += 1
    pygame.display.update()


def switch_board(first_block_coordinates, second_block_coordinates): #switches the locations of two valid square selections
    global grid_colors
    global moves
    sq1 = False
    sq2 = False
    corner_squares = [0, (difficulty[difficulty_selected] - 1), ((difficulty[difficulty_selected]**2)-1) - (difficulty[difficulty_selected] - 1), difficulty[difficulty_selected]**2 - 1]
    for num in range(difficulty[difficulty_selected]**2 - 1):
        if num not in corner_squares:
            if grid_colors[num][3] == first_block_coordinates[0] and grid_colors[num][4] == first_block_coordinates[1]:
                sq1 = num
            if grid_colors[num][3] == second_block_coordinates[0] and grid_colors[num][4] == second_block_coordinates[1]:
                sq2 = num
    if sq1 != False and sq2 != False:
        grid_colors[sq1][:3], grid_colors[sq2][:3] = grid_colors[sq2][:3], grid_colors[sq1][:3]
        grid_to_board()
    else:
        print("You cannot alter a corner square. They are your guide!")
        moves -= 1 #don't want to count a move if the move was used on an invalid corner_square selection

def shuffle_board(): #randomizes the positions of all squares except four corners
    four_corner_squares = [0, (difficulty[difficulty_selected] - 1), ((difficulty[difficulty_selected]**2)-1) - (difficulty[difficulty_selected] - 1), difficulty[difficulty_selected]**2 - 1]
    for each_square in grid_colors[:]:
        if each_square not in four_corner_squares:
            first_square = random.randint(0, difficulty[difficulty_selected]**2-1)
            second_square = random.randint(0, difficulty[difficulty_selected]**2-1)
            if first_square not in four_corner_squares and second_square not in four_corner_squares:
                grid_colors[first_square][:3], grid_colors[second_square][:3] = grid_colors[second_square][:3], grid_colors[first_square][:3]
    pygame.display.update()


start_game = False
grid_not_loaded = True
board_drawn = False
block_chosen = False


while grid_not_loaded:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            grid_not_loaded = False
            pygame.quit()
            sys.exit() #is supposed to exit the "system" / window - change "sys" to respective system name
        elif board_drawn == False:
            WHITE_upper_left = [255,255,255]
            lower_left = color1
            upper_right = color2
            BLACK_lower_right = [0,0,0]
            draw_board(list(WHITE_upper_left), list(lower_left), list(upper_right), list(BLACK_lower_right))
        if event.type == pygame.MOUSEBUTTONDOWN:
            shuffle_board()
            grid_to_board()
            board_drawn = True
            start_game = True #STARTS NEXT "WHILE" LOOP
            grid_not_loaded = False

moves = 0

while start_game:
    global row
    global column
    global row2
    global column2 
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            moves = 0
            pygame.quit()
            sys.exit()
        elif event.type == pygame.MOUSEBUTTONDOWN and block_chosen == False:
            block_chosen = True
            pos = pygame.mouse.get_pos()
            column = pos[0] // (square_width + margin)
            row = pos[1] // (square_height + margin)
            block1_row = (screen_height // difficulty[difficulty_selected]) * row #LeftHand corner of block that the click is contained in (so selected rectangle draws in correct spot)
            block1_column = (screen_width // difficulty[difficulty_selected]) * column
            block_1 = [block1_row, block1_column]
            pygame.draw.rect(screen, WHITE, [block_1[1] + margin, block_1[0] + margin, square_width, square_height], 2) #outlines the first selected square
            pygame.display.update()
        elif event.type == pygame.MOUSEBUTTONDOWN and block_chosen == True:
            pos2 = pygame.mouse.get_pos()
            column2 = pos2[0] // (square_width + margin)
            row2 = pos2[1] // (square_height + margin)
            switch_board([row, column], [row2, column2])
            block_chosen = False
            moves += 1
            pygame.display.update()
            if grid_colors[:] == game_winning_grid[:]:
                print("CONGRATULATIONS! You completed the grid in "+ str(moves) +" moves!")
                moves = 0
                pygame.quit()
                start_game = False

beginner code =/= most efficient code