<reponame>Zanyguy/kivy_match_app<gh_stars>0
import random
from kivy.app import App
from kivy.animation import Animation
from MatchApp import newShapes as nShapes


def validMove(origin, partner, board):
    """ Confirms that move is only one vertical or horizontal space away,
        and that it results in a match"""
    if (partner.row == origin.row-1 or partner.row==origin.row+1
        ) and partner.column == origin.column:
        singleMove(origin, partner, board, test=True)
        matchList = getMatches(board)
        singleMove(origin, partner, board, test=True)
        if len(matchList):
            return True

    elif ((partner.column == origin.column-1 or partner.column == origin.column+1
           ) and partner.row == origin.row):
        singleMove(origin, partner, board, test=True)
        matchList = getMatches(board)
        singleMove(origin, partner, board, test=True)
        if len(matchList):
            return True


def singleMove(origin, partner, board, test=False):
    """Swaps a selected widget with a selected neighbor. Use the 'test'
        parameter to prevent screen updating"""
    brd = board.brd

    C = (partner.column,partner.row)
    S = (origin.column,origin.row)
    
    brd[C], brd[S] = brd[S], brd[C]

    partner.row, origin.row = origin.row, partner.row
    partner.column, origin.column = origin.column, partner.column
    if test==False:
        updateBoard(board)

def matchFactory(origin, partner, board):
    """Called on valid moves to get all matches and cascades and call
        screen updates"""
    matchList = getMatches(board)
    while len(matchList):
        matchesDown(matchList, board)
        matchList = getMatches(board)
        updateBoard(board)
    partner.state = 'normal'
    origin.state = 'normal'

def updateBoard(board, *args, **kwargs):
    """Animation factory to update widget locations after swaps and drops"""
    animlist =[]
    brd = board.brd
    for key, child in brd.items():
        if child.pos != (((board.width*.1)*child.column),((board.height*.1)*(child.row-1))):
            X = .1*child.column
            Y = .1*(child.row)
            anim = Animation(pos_hint={'x': X,'y': Y},
                             duration = .25)
            animlist.append([anim, child])
    board.AQ.animations.append(animlist)
    board.AQ.dropping = True


def getMatches(board, *args):
    """Search algorithm to find all matches on the board. Implements a
       variation of a flood fill algorithm."""
    matches = []
    brd = board.brd
#horizontal matches
    for y in range(1,9):
        for x in range(1,9):
            shape = brd[(x,y)].shape
            if shape !=0:
                match = []
                i = x
                while i < (9):
                    if brd[(i,y)].shape == shape:
                        match.append(brd[(i,y)])
                    else:
                        break
                    i += 1
                if len(match) > 2:
                    x = i+1
                    matches.append(match)
# vertical matches
    for x in range(1,9):
        for y in range(1,9):
            shape = brd[(x,y)].shape
            if shape != 0:
                match = []
                i = y
                while i < (9):
                    if brd[(x,i)].shape == shape:
                        match.append(brd[(x,i)])
                    else:
                        break
                    i += 1

                if len(match) > 2:
                    y = i+1
                    matches.append(match)
    return matches


def matchesDown(matches, board):
    """Animation factory for match removal. Accepts a list of lists,
    of widgets, as generated by 'getMatches()'."""
    animlist = []
    i = 0
    while i < len(matches):
        n = 0
        while n < len(matches[i]):
            anim = Animation(width=0, height=0, duration = .25)
            child = matches[i][n]
            child.size_hint = (None, None)
            animlist.append([anim, child])
            child.shape = 0

            n+=1
        child.parent.score.text = str(int(child.parent.score.text)+(n*150))
        child.parent.AQ.animations.append(animlist)
        animlist=[]
        i+=1
    nShapes(board)

def cleanFirstBoard(board, *args):
    """Removes initial matches on app build, and resets score to 0"""
    matches = getMatches(board)
    while len(matches):
        matchesDown(matches, board)
        updateBoard(board)
        matches = getMatches(board)

def checkShapes(brd, x, y, s2, *args):
    s1 = str(x)+','+str(y)
    if s1 in brd:
        if brd[s1].shape==s2:
            return True


def getPotentialMatches(board, *args):
    """Search algorithm to find all potential matches on the board. """
    matches = []
    brd = board.brd
#horizontal potential matches
    for y in range(1,9):
        for x in range(1,9):
            shape = brd[(x,y)].shape
            if shape !=0:
                match = []
                if checkShapes(brd, x+1, y, shape) and (
                         checkShapes(brd, x+2, y+1, shape) or
                         checkShapes(brd, x+3, y, shape) or
                         checkShapes(brd, x+2, y-1, shape)
                         ):
                    return True
                        
                elif checkShapes(brd, x+2, y, shape) and (
                            checkShapes(brd, x+1, y+1, shape) or
                            checkShapes(brd, x+3, y, shape) or
                            checkShapes(brd, x+1, y-1, shape)
                            ):
                    return True
                
                elif ((checkShapes(brd, x+1, y+1, shape) and 
                            checkShapes(brd, x+2, y+1, shape)) or
                            (checkShapes(brd, x-1, y-1, shape) and
                             checkShapes(brd, x+2, y-1, shape))):
                    return True
                        
# vertical potential matches
    for x in range(1,9):
        for y in range(1,9):
            shape = brd[(x,y)].shape
            if shape !=0:

                if checkShapes(brd, x, y+1, shape) and (
                            checkShapes(brd, x+1, y+2, shape) or
                            checkShapes(brd, x, y+3, shape) or
                            checkShapes(brd, x-1, y+2, shape)
                            ):
                    return True
                            
                elif checkShapes(brd, x, y+2, shape) and (
                            checkShapes(brd, x+1, y+1, shape) or
                            checkShapes(brd, x, y+3, shape) or
                            checkShapes(brd, x-1, y+1, shape)
                            ):
                    return True
                            
                elif ((checkShapes(brd, x+1, y+1, shape) and 
                            checkShapes(brd, x+1, y+2, shape)) or
                            (checkShapes(brd, x-1, y+1, shape) and
                             checkShapes(brd, x-1, y+2, shape))):
                    return True
    return False
