# Ink Spill (Flood It Clone)
# http://inventwithpython.com/blog
# By Al Sweigart al@inventwithpython.com
# Creative Commons US BY-NC-SA 3.0

# Ubuntu, Mint : sudo apt install python-pygame

import random
import time
import sys
import pygame
from pygame.locals import *
import webbrowser



SMALLBOXSIZE 60
MEDIUMBOXSIZE 20
LARGEBOXSIZE 11

SMALLCOLSROWS 6
MEDIUMCOLSROWS 17
LARGECOLSROWS 30

SMALLMAXLIFE 10
MEDIUMMAXLIFE 30
LARGEMAXLIFE 64

FPS 30
WINDOWWIDTH 640
WINDOWHEIGHT 480
BOXSIZE 20
PALETTEGAPSIZE 10
PALETTESIZE 45
MAXLIFE 30
COLS 17
ROWS 17
DIFFICULTY 1


WHITE = (255255255)
DARKGRAY = (707070)
BLACK = (000)
RED = (25500)
GREEN = (02550)
BLUE = (00255)
YELLOW = (2552550)
ORANGE = (2551280)
PURPLE = (2550255)

COLORS = (REDGREENBLUEYELLOWORANGEPURPLE)
BGCOLOR = (150200255)

COLORSCHEMES = (((150200255), REDGREENBLUEYELLOWORANGEPURPLE),
                ((0155104), (97215164), (228069), (012550), (2042460), (148045), (241109149)),
                ((1951790), (255239115), (2552260), (1473167), (2438176), (1661470), (19797211)),
                ((8500), (15539102), (020113), (2551180), (2060113), (01309), (255180115)),
                ((19115964), (183182208), (431183), (16718445), (122128212),(372047), (88155213)),
                ((20033205),  (116252185),  (685656),  (5223883),  (23149195),  (222157227),  (21286185)))

def main():
    global MAINCLOCKMAINSURF

    pygame.init()
    MAINCLOCK pygame.time.Clock()
    MAINSURF pygame.display.set_mode((WINDOWWIDTHWINDOWHEIGHT))
    loadImages()

    pygame.display.set_caption('Ink Spill')
    mousex 0
    mousey 0
    mainBoard generateRandomBoard(COLSROWSDIFFICULTY)
    life MAXLIFE
    lastPaletteClicked None

    # Main game loop:
    while True:
        paletteClicked None
        resetGame False

        # Draw the screen.
        MAINSURF.fill(BGCOLOR)
        drawLogo()
        drawBoard(mainBoard)
        drawLifeMeter(life)
        drawPalettes()

        # Handle any events.
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()

            if event.type == MOUSEMOTION:
                mousexmousey event.pos
            if event.type == MOUSEBUTTONUP:
                mousexmousey event.pos
                if pygame.Rect(WINDOWWIDTH SETTINGSBUTTONIMAGE.get_width(),
                               WINDOWHEIGHT SETTINGSBUTTONIMAGE.get_height(),
                               SETTINGSBUTTONIMAGE.get_width(),
                               SETTINGSBUTTONIMAGE.get_height()).collidepoint(mousexmousey):
                    resetGame showSettingsScreen()
                elif pygame.Rect(WINDOWWIDTH RESETBUTTONIMAGE.get_width(),
                                 WINDOWHEIGHT SETTINGSBUTTONIMAGE.get_height() - RESETBUTTONIMAGE.get_height(),
                                 RESETBUTTONIMAGE.get_width(),
                                 RESETBUTTONIMAGE.get_height()).collidepoint(mousexmousey):
                    resetGame True
                else:
                    paletteClicked getClickedPalette(mousexmousey)
            if event.type == KEYUP:
                if event.key == K_ESCAPE:
                    terminate()

        if paletteClicked != None and paletteClicked != lastPaletteClicked:
            lastPaletteClicked paletteClicked
            floodAnimation(mainBoardpaletteClicked)
            life -= 1

            resetGame False
            if hasWon(mainBoard):
                for in range(4):
                    flashBorderAnimation(WHITEmainBoard)
                resetGame True
                time.sleep(2)
            elif life == 0:
                drawLifeMeter(0)
                pygame.display.update()
                time.sleep(0.4)
                for in range(4):
                    flashBorderAnimation(BLACKmainBoard)
                resetGame True
                time.sleep(2)

        if resetGame:
            mainBoard generateRandomBoard(COLSROWSDIFFICULTY)
            life MAXLIFE
            lastPaletteClicked None

        pygame.display.update()
        MAINCLOCK.tick(FPS)

def loadImages():
    global LOGOIMAGENOLOGOSPOTIMAGESETTINGSIMAGESETTINGSBUTTONIMAGERESETBUTTONIMAGE

    NOLOGO False
    try:
        LOGOIMAGE pygame.image.load('inkspilllogo.png')
    except pygame.error:
        NOLOGO True
    SPOTIMAGE pygame.image.load('inkspillspot.png')
    SETTINGSIMAGE pygame.image.load('inkspillsettings.png')
    SETTINGSBUTTONIMAGE pygame.image.load('inkspillsettingsbutton.png')
    RESETBUTTONIMAGE pygame.image.load('inkspillresetbutton.png')

def terminate():
    pygame.quit()
    sys.exit()

def hasWon(board):
    color board[0][0]
    for in range(COLS):
        for in range(ROWS):
            if board[x][y] != color:
                return False
    return True

def showSettingsScreen():
    global DIFFICULTYBOXSIZECOLSROWSMAXLIFECOLORSBGCOLOR

    origDifficulty DIFFICULTY
    origBoxSize BOXSIZE

    while True:
        MAINSURF.fill(BGCOLOR)
        MAINSURF.blit(SETTINGSIMAGE, (0,0))

        if DIFFICULTY == 0:
            MAINSURF.blit(SPOTIMAGE, (304))
        if DIFFICULTY == 1:
            MAINSURF.blit(SPOTIMAGE, (841))
        if DIFFICULTY == 2:
            MAINSURF.blit(SPOTIMAGE, (3076))

        if BOXSIZE == SMALLBOXSIZE:
            MAINSURF.blit(SPOTIMAGE, (22150))
        if BOXSIZE == MEDIUMBOXSIZE:
            MAINSURF.blit(SPOTIMAGE, (11185))
        if BOXSIZE == LARGEBOXSIZE:
            MAINSURF.blit(SPOTIMAGE, (24220))

        for in range(len(COLORSCHEMES)):
            drawColorSchemeBoxes(50060 30i)

        pygame.display.update()

        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            if event.type == KEYUP:
                if event.key == K_ESCAPE:
                    return not (origDifficulty == DIFFICULTY and origBoxSize == BOXSIZE)
            if event.type == MOUSEBUTTONUP:
                mousexmousey event.pos
                if pygame.Rect(741611130).collidepoint(mousexmousey):
                    DIFFICULTY 0
                if pygame.Rect(535010429).collidepoint(mousexmousey):
                    DIFFICULTY 1
                if pygame.Rect(72856531).collidepoint(mousexmousey):
                    DIFFICULTY 2
                if pygame.Rect(631568431).collidepoint(mousexmousey):
                    BOXSIZE SMALLBOXSIZE
                    COLS SMALLCOLSROWS
                    ROWS SMALLCOLSROWS
                    MAXLIFE SMALLMAXLIFE
                if pygame.Rect(52192106,32).collidepoint(mousexmousey):
                    BOXSIZE MEDIUMBOXSIZE
                    COLS MEDIUMCOLSROWS
                    ROWS MEDIUMCOLSROWS
                    MAXLIFE MEDIUMMAXLIFE
                if pygame.Rect(672285837).collidepoint(mousexmousey):
                    BOXSIZE LARGEBOXSIZE
                    COLS LARGECOLSROWS
                    ROWS LARGECOLSROWS
                    MAXLIFE LARGEMAXLIFE

                for in range(len(COLORSCHEMES)):
                    if pygame.Rect(50030 60MEDIUMBOXSIZE 3MEDIUMBOXSIZE 2).collidepoint(mousexmousey):
                        COLORS COLORSCHEMES[i][1:]
                        BGCOLOR COLORSCHEMES[i][0]

                if pygame.Rect(1429937197).collidepoint(mousexmousey):
                    webbrowser.open('http://inventwithpython.com')
                if pygame.Rect(17841821534).collidepoint(mousexmousey):
                    return not (origDifficulty == DIFFICULTY and origBoxSize == BOXSIZE)




def drawColorSchemeBoxes(xyschemeNum):
    for boxy in range(2):
        for boxx in range(3):
            pygame.draw.rect(MAINSURFCOLORSCHEMES[schemeNum][boxy boxx 1], (MEDIUMBOXSIZE boxxMEDIUMBOXSIZE boxyMEDIUMBOXSIZEMEDIUMBOXSIZE))
            if COLORS == COLORSCHEMES[schemeNum][1:]:
                MAINSURF.blit(SPOTIMAGE, (50y))

def flashBorderAnimation(colorboardanimationSpeed=30):
    origSurf MAINSURF.copy()
    flashSurf pygame.Surface(MAINSURF.get_size())
    flashSurf flashSurf.convert_alpha()
    for startendstep in ((02561), (2550, -1)):
        for transparency in range(startendanimationSpeed step):
            MAINSURF.blit(origSurf, (00))
            rgcolor
            flashSurf.fill((rgbtransparency))
            MAINSURF.blit(flashSurf, (00))
            drawBoard(board)
            pygame.display.update()
            MAINCLOCK.tick(FPS)
    MAINSURF.blit(origSurf, (00))

def getBoardCopy(board):
    dupe = []
    for in range(COLS):
        column = []
        for in range(ROWS):
            column.append(board[x][y])
        dupe.append(column)
    return dupe

def floodAnimation(boardpaletteClickedanimationSpeed=25):
    origBoard getBoardCopy(board)
    flood(boardboard[0][0], paletteClicked00)

    for transparency in range(0255animationSpeed):
        drawBoard(origBoard)
        drawBoard(boardtransparency)
        pygame.display.update()
        MAINCLOCK.tick(FPS)

def generateRandomBoard(widthheightdifficulty=1):
    board = []
    for in range(width):
        column = []
        for in range(height):
            column.append(random.randint(0len(COLORS) - 1))
        board.append(column)

    # Make the board easier by setting some boxes to be the same color as their neighbor.
    if difficulty == 0:
        difficulty 1500
    elif difficulty == 1:
        difficulty 200
    if difficulty == and BOXSIZE == SMALLBOXSIZE:
        difficulty 100
    elif difficulty == and BOXSIZE == SMALLBOXSIZE:
        difficulty 5
    elif BOXSIZE == LARGEBOXSIZE:
        difficulty *= 8
    else:
        difficulty 0



    for in range(difficulty):
        random.randint(1width-2)
        random.randint(1height-2)
        direction random.randint(03)

        if direction == 0:
            board[x-1][y] == board[x][y]
            board[x][y-1] == board[x][y]
        elif direction == 1:
            board[x+1][y] == board[x][y]
            board[x][y+1] == board[x][y]
        elif direction == 2:
            board[x][y-1] == board[x][y]
            board[x+1][y] == board[x][y]
        else:
            board[x][y+1] == board[x][y]
            board[x-1][y] == board[x][y]

    return board

def drawLogo():
    if not NOLOGO:
        MAINSURF.blit(LOGOIMAGE, (WINDOWWIDTH LOGOIMAGE.get_width(), 0))
    MAINSURF.blit(SETTINGSBUTTONIMAGE, (WINDOWWIDTH SETTINGSBUTTONIMAGE.get_width(), WINDOWHEIGHT SETTINGSBUTTONIMAGE.get_height()))
    MAINSURF.blit(RESETBUTTONIMAGE, (WINDOWWIDTH RESETBUTTONIMAGE.get_width(), WINDOWHEIGHT SETTINGSBUTTONIMAGE.get_height() - RESETBUTTONIMAGE.get_height()))

def drawBoard(boardtransparency=255):
    tempSurf pygame.Surface(MAINSURF.get_size())
    tempSurf tempSurf.convert_alpha()
    tempSurf.fill((0000))

    for in range(COLS):
        for in range(ROWS):
            lefttop leftTopOfBox(xy)
            rgCOLORS[board[x][y]]
            pygame.draw.rect(tempSurf, (rgbtransparency), (lefttopBOXSIZEBOXSIZE))
    lefttop leftTopOfBox(00)
    pygame.draw.rect(tempSurfBLACK, (left-1top-1BOXSIZE COLS 1BOXSIZE ROWS 1), 1)
    MAINSURF.blit(tempSurf, (00))

def drawPalettes():
    numColors len(COLORS)
    xmargin int((WINDOWWIDTH - ((PALETTESIZE numColors) + (PALETTEGAPSIZE * (numColors 1)))) / 2)
    for in range(numColors):
        left xmargin + (PALETTESIZE) + (PALETTEGAPSIZE)
        top WINDOWHEIGHT PALETTESIZE 10
        pygame.draw.rect(MAINSURFCOLORS[i], (lefttopPALETTESIZEPALETTESIZE))
        pygame.draw.rect(MAINSURFBGCOLOR,   (left 2top 2PALETTESIZE 4PALETTESIZE 4), 2)

def drawLifeMeter(currentLife):
    lifeBoxSize int((WINDOWHEIGHT 40) / MAXLIFE)

    # Draw background of life box.
    pygame.draw.rect(MAINSURFBGCOLOR, (20202020 + (MAXLIFE lifeBoxSize)))

    for in range(MAXLIFE):
        if currentLife >= (MAXLIFE i):
            pygame.draw.rect(MAINSURFRED, (2020 + (lifeBoxSize), 20lifeBoxSize))
        pygame.draw.rect(MAINSURFWHITE, (2020 + (lifeBoxSize), 20lifeBoxSize), 1)

def getClickedPalette(xy):
    numColors len(COLORS)
    xmargin int((WINDOWWIDTH - ((PALETTESIZE numColors) + (PALETTEGAPSIZE * (numColors 1)))) / 2)
    top WINDOWHEIGHT PALETTESIZE 10
    for in range(numColors):
        # Determine if the xy coordinates of the mouse click is inside any of the palettes.
        left xmargin + (PALETTESIZE) + (PALETTEGAPSIZE)
        pygame.Rect(lefttopPALETTESIZEPALETTESIZE)
        if r.collidepoint(xy):
            return i
    return None

def flood(boardoldColorNumnewColorNumxy):
    if oldColorNum == newColorNum or board[x][y] != oldColorNum:
        return

    board[x][y] = newColorNum # change the color of the current box

    # Make the recursive call for any neighboring boxes:
    if 0:
        flood(boardoldColorNumnewColorNum1y)
    if COLS 1:
        flood(boardoldColorNumnewColorNum1y)
    if 0:
        flood(boardoldColorNumnewColorNumx1)
    if ROWS 1:
        flood(boardoldColorNumnewColorNumx1)

def leftTopOfBox(boxxboxy):
    # Determine size of the margins for each side.
    xmargin int((WINDOWWIDTH - (COLS BOXSIZE)) / 2)
    ymargin int((WINDOWHEIGHT - (ROWS BOXSIZE)) / 2)
    return (boxx BOXSIZE xmarginboxy BOXSIZE ymargin)

if __name__ == '__main__':
    main()