import pyxel
from pyxel import KEY_SPACE, KEY_LEFT, KEY_RIGHT

# taille de la fenetre 168x168 pixels
# ne pas modifier
pyxel.init(168, 168, title="Puissance 4") #168 car divisible par 7 = 24

# Variables initiales
grille_x = 0
grille_y = 20
# trou_x = 16
# trou_y = 25
tableau_width = 168
tableau_hight = 150
# Configuración de la cuadrícula
Colone = 7
Ligne = 6
# Rayon trou
Trou_R = 8
# Distance entre trou
Dist_X = tableau_width // Colone  #168//7 = 24
Dist_Y = tableau_hight // Ligne   #150//6 = 25
Marge_haut = 4


#pyxel.load("[Puissance4].pyxres")  SI NECESSAIRE LE FICHIER EXISTE


# j1 = jaune et j2 = rouge
menu = True #faut pas nonplus tout expliquer non?
counter = 0 #Compte a rebour pour le menu... Affichage
win_play = "personne" #Le joueur qui gagne la partie
vict_p1 = 0 #NB de Victoires
vict_p2 = 0 #NB de Victoires
tour = 0  # pour savoir qui joue son tour
pos_jetons_j = [[],[],[]]  # positions jetons jaunes (j1)   i = 0 pour le placement i = 1 pour quand le jeton tombe (animation) et i = 2 pour la pos definitive
pos_jetons_r = [[],[],[]]  # pos jetons rouges (joueur 2)   i = 0 pour le placement i = 1 pour quand le jeton tombe (animation) et i = 2 pour la pos definitive
positions_simplifees = [
   [0,0,0,0,0,0,0],
   [0,0,0,0,0,0,0],
   [0,0,0,0,0,0,0],
   [0,0,0,0,0,0,0],
   [0,0,0,0,0,0,0],
   [0,0,0,0,0,0,0]
]  # Simplification par 0 1 ou 2 pour indiquer type de jeton, 0 = vide, 1 = eq 1 et 2 = eq 2
bottom = 0 #Definit si ou pas un jeton peut descendre et la profondeur maximale
GAME_OVER = False #Rien a expliquer
Tour_Jouable = False #Definit si un tour est jouable, depend de bottom
tour_change = True #Definit si le tour d'un joueur est actif
place_mode = True #mode placement


def find_bottom(pos_jetons_j, pos_jetons_r):
   """
   Pour connaitre y max , fond du tab variable car il peut y avoir un jeton en dessous
   :param pos_jetons_j:  positions jetons jaunes (j1)   i = 0 pour le placement i = 1 pour quand le jeton tombe (animation) et i = 2 pour la pos definitive
   :param pos_jetons_r:  pos jetons rouges (joueur 2)   i = 0 pour le placement i = 1 pour quand le jeton tombe (animation) et i = 2 pour la pos definitive
   :return: BOTTOM, y max
   """
   bottom = 7 + 6*25
   for jeton_mouvement in pos_jetons_j[1] + pos_jetons_r[1]:
       for jeton in pos_jetons_j[2] + pos_jetons_r[2]:
           if jeton[0] == jeton_mouvement[0]:  # check colomne
               bottom = min(bottom, jeton[1] - 25)
   if len(pos_jetons_r[0]) or len(pos_jetons_j[0]) > 0:
       for jeton in pos_jetons_j[2] + pos_jetons_r[2]:
           for jeton_mouvement in pos_jetons_j[0] + pos_jetons_r[0]:
               if jeton[0] == jeton_mouvement[0]:  # check colomne
                   if jeton[1] == 7 + 25:
                       bottom = 0




   return bottom


def tour_r(pos_jetons_j, pos_jetons_r, tour, tour_change, bottom, place_mode):
  """
  Prend touts les parametres de listes de jeton pour executer la phase du joueur r ou j selon le nom de la fonction, definit si l'on
  a besoin de generer un jeton pour le jouer puis offre la fonctionalite de le placer avec les flechettes avant d'appuyer sur espace pour le decaler a la liste indexe
  1 de la liste de la couleur du joueur, une fois dans la liste 1 le tour du joueur finit
  :param pos_jetons_j:
  :param pos_jetons_r:
  :param tour:
  :param tour_change:
  :param bottom:
  :param place_mode:
  :return:
  """
  if tour % 2 == 0 and place_mode == True:
      # POUR SAVOIR QUI JOUE
      if tour_change == True:
       pos_jetons_j[0].append([84, 7])
       tour_change = False
      if pyxel.btnr(KEY_SPACE) and find_bottom(pos_jetons_j,pos_jetons_r) > 8+25:
          pos_jetons_j[1].append(pos_jetons_j[0][0])
          pos_jetons_j[0].pop(0)
          place_mode = False
          tour += 1
          return pos_jetons_j, pos_jetons_r, tour, tour_change, bottom, place_mode
      if pyxel.btnr(KEY_LEFT) and pos_jetons_j[0][0][0] > 23: #bouger la piece une fois vers left si les conditions mode actif et pas trop left sont vraies
       pos_jetons_j[0][0][0] -= 24
      if pyxel.btnr(KEY_RIGHT) and  pos_jetons_j[0][0][0] < 168 - 24: #bouger la piece une fois vers right si les conditions mode actif et pas trop right sont vraies
          pos_jetons_j[0][0][0] += 24
      return pos_jetons_j, pos_jetons_r, tour, tour_change, bottom, place_mode
  return pos_jetons_j, pos_jetons_r, tour, tour_change, bottom, place_mode


def tour_j(pos_jetons_j, pos_jetons_r, tour, tour_change, bottom, place_mode):
  """
  Prend touts les parametres de listes de jeton pour executer la phase du joueur r ou j selon le nom de la fonction, definit si l'on
  a besoin de generer un jeton pour le jouer puis offre la fonctionalite de le placer avec les flechettes avant d'appuyer sur espace pour le decaler a la liste indexe
  1 de la liste de la couleur du joueur, une fois dans la liste 1 le tour du joueur finit
  :param pos_jetons_j:
  :param pos_jetons_r:
  :param tour:
  :param tour_change:
  :param bottom:
  :param place_mode:
  :return:
  """
  if tour % 2 == 1 and place_mode == True: # POUR SAVOIR QUI JOUE
      if tour_change == True:
          pos_jetons_r[0].append([84, 7])
          tour_change = False
      if pyxel.btnr(KEY_SPACE) and find_bottom(pos_jetons_j,pos_jetons_r) > 25:
          pos_jetons_r[1].append(pos_jetons_r[0][0])
          pos_jetons_r[0].pop(0)
          place_mode = False
          tour += 1
          return pos_jetons_j, pos_jetons_r, tour, tour_change, bottom, place_mode
      if pyxel.btnr(KEY_LEFT) and pos_jetons_r[0][0][0] > 23: #bouger la piece une fois vers left si les conditions mode actif et pas trop left sont vraies
          pos_jetons_r[0][0][0] -= 24
      if pyxel.btnr(KEY_RIGHT) and  pos_jetons_r[0][0][0] < 168 - 24: #bouger la piece une fois vers right si les conditions mode actif et pas trop right sont vraies
          pos_jetons_r[0][0][0] += 24
      return pos_jetons_j, pos_jetons_r, tour, tour_change, bottom, place_mode
  return pos_jetons_j, pos_jetons_r, tour, tour_change, bottom, place_mode


def tombee_r(pos_jetons_r,bottom,tour_change,place_mode, pos_jetons_j):
   """
   Prend la liste de pions et si il y a des jetons dans l'indexe 1 il commence la tombee jsq le max de profondeur y, definit par find_bottom()
   :param pos_jetons_r:
   :param bottom:
   :param tour_change:
   :param place_mode:
   :param pos_jetons_j:
   :return:
   """
   bottom = 0
   if len(pos_jetons_r[1]) > 0:
       for jeton in pos_jetons_r[1]:
           if jeton[1] < find_bottom(pos_jetons_j,pos_jetons_r):
               jeton[1] += 25
               #TOMBE
               break
           if  jeton[1] == find_bottom(pos_jetons_j,pos_jetons_r):
               #FIN CHUTE
               pos_jetons_r[2].append(pos_jetons_r[1][0])
               pos_jetons_r[1].pop(0)
               tour_change = place_mode = True
   return pos_jetons_r, bottom,tour_change,place_mode, pos_jetons_j


def tombee_j(pos_jetons_j,bottom,tour_change,place_mode, pos_jetons_r):
   """
   Prend la liste de pions et si il y a des jetons dans l'indexe 1 il commence la tombee jsq le max de profondeur y, definit par find_bottom()
   :param pos_jetons_r:
   :param bottom:
   :param tour_change:
   :param place_mode:
   :param pos_jetons_j:
   :return:
   """
   bottom = 0
   if len(pos_jetons_j[1]) > 0:
       for jeton in pos_jetons_j[1]:
           if jeton[1] < find_bottom(pos_jetons_j,pos_jetons_r):
               jeton[1] += 25
               #TOMBE
               break
           if jeton[1] == find_bottom(pos_jetons_j,pos_jetons_r):
               #FIN CHUTE
               pos_jetons_j[2].append(pos_jetons_j[1][0])
               pos_jetons_j[1].pop(0)
               tour_change = place_mode = True
   return pos_jetons_j, bottom,tour_change,place_mode, pos_jetons_r


def simplificateur(pos_jetons_j,pos_jetons_r,positions_simplifees):
   """Simplifie les calculs de puissance 4 par simplifiant le tableau que l'ordinateur va calculer
   1 pour jaune 2 pour rouge et 0 pour vide"""
   ligne = 0
   colonne = 0
   for jeton in pos_jetons_j[2]:
       if jeton:
           ligne = (jeton[1] - 32) // 25 #32 etant la separation entre la zone selection position et la zone des jetons, 25 etant l'espace entre case jouable y
           colonne = (jeton[0] - 12) // 24 #32 etant la separation entre le bord de l'ecran et la zone des jetons, 24 etant l'espace entre case jouable x
           positions_simplifees[ligne][colonne] = 1 #Remplace 0 par 1
   for jeton in pos_jetons_r[2]:
       if jeton:
           ligne = (jeton[1] - 32) // 25 #32 etant la separation entre la zone selection position et la zone des jetons, 25 etant l'espace entre case jouable y
           colonne = (jeton[0] - 12) // 24 #32 etant la separation entre le bord de l'ecran et la zone des jetons, 24 etant l'espace entre case jouable x
           positions_simplifees[ligne][colonne] = 2 #Remplace 0 par 2
#    if pyxel.frame_count % 30 == 0:
#        print(positions_simplifees,"    ", ligne, " ",colonne)
#   lignes pour debeuguer les positions, visualisation des pos simplifiees 1 fois par sec
   return positions_simplifees


def detection_victoire():
   """
   Va verifier si il y a un gagnant et va nommer le gagnant
   Si le jeton annalise est jaune il va verifier si les jetons jaunes sont allignes
   Si le jeton annalise est Rouge il va verifier si les jetons Rouges sont allignes
   :return: Le gagnant de la partie sous forme de STR
   """
   global positions_simplifees
   winner = "personne"
   for i in range(6):
       for j in range(7):
           if not 0 in positions_simplifees[i]:
               winner = "0"
           if positions_simplifees[i][j] == 1:
               if test_pos(i,j,1):
                   winner = "Joueur Jaune"
           if positions_simplifees[i][j] == 2:
               if test_pos(i,j,2):
                   winner = "Joueur Rouge"
   return winner


def test_pos(i,j,valeur):
   """
   La fonction va verifier TOUT pion qui lui est envoye pour voir si ce pion a 4 voisins allignes, il va verifier seuelemnt une fois axe x, une fois axe y
   et aussi les 4 diagonales possibles avec 1+d / i-d et j+d / j-d
   :param i: position sur y
   :param j: pos sur x
   :param valeur: couleur du jeton vise
   :return: True ou False selon nb de jetons allignes, True if jetons allignes = 4


   Le compteur doit TOUJOURS commencer a  = 1
   """
   global positions_simplifees
   compteur_jetons = 1 # vaut 1 car le test demarre considerant deja la position de 1 jeton valeur
   for d in range(1,4):
       # 1 a 4-1 car on sait deja que i+0 = i et j+0 = j
       if j+d < 7:
           if positions_simplifees[i][j+d] == valeur:
               compteur_jetons += 1
   if compteur_jetons != 4:
       compteur_jetons = 1
   for d in range(1, 4):
       if i+d < 6:
           if positions_simplifees[i+d][j] == valeur:
               compteur_jetons += 1
   if compteur_jetons == 4:
       return True
   else:
       compteur_jetons = 1
       for d in range(1, 4):
           # 1 a 4-1 car on sait deja que i+0 = i et j+0 = j
           if j + d < 7 and i + d < 6:
               if positions_simplifees[i + d][j + d] == valeur:
                   compteur_jetons += 1
       if compteur_jetons != 4:
           compteur_jetons = 1
           for d in range(1, 4):
               if j - d >= 0 and i - d >= 0:
                   if positions_simplifees[i - d][j - d] == valeur:
                       compteur_jetons += 1
       if compteur_jetons != 4:
           compteur_jetons = 1
           for d in range(1, 4):
               if i + d < 6 and j - d >= 0:
                   if positions_simplifees[i + d][j - d] == valeur:
                       compteur_jetons += 1
       if compteur_jetons != 4:
           compteur_jetons = 1
           for d in range(1, 4):
               if i - d >= 0 and j + d < 7:
                   if positions_simplifees[i - d][j + d] == valeur:
                       compteur_jetons += 1
   if compteur_jetons == 4:
       return True
   else:
       return False


# =========================================================
# == UPDATE ===============================================
# =========================================================
def update():
  """
  mise à jour des variables (30 fois par seconde)
  :return: TOUT (presque, sous forme de Global)
  """
  global menu, counter, vict_p1, vict_p2, win_play, pos_jetons_r, pos_jetons_j,  tour, bottom, GAME_OVER , tour_change, place_mode, positions_simplifees


  if tour % 2 == 0 and menu == False and counter == 0:
      pos_jetons_j , pos_jetons_r , tour , tour_change, bottom, place_mode = tour_r(pos_jetons_j, pos_jetons_r, tour, tour_change, bottom, place_mode)
  if tour % 2 == 1 and menu == False and counter == 0:
      pos_jetons_j , pos_jetons_r , tour , tour_change, bottom, place_mode = tour_j(pos_jetons_j, pos_jetons_r, tour, tour_change, bottom, place_mode)


  pos_jetons_r, bottom, tour_change, place_mode, pos_jetons_j= tombee_r(pos_jetons_r,bottom,tour_change,place_mode, pos_jetons_j)
  pos_jetons_j, bottom, tour_change, place_mode, pos_jetons_r = tombee_j(pos_jetons_j,bottom,tour_change,place_mode, pos_jetons_r)
  positions_simplifees = simplificateur(pos_jetons_j,pos_jetons_r,positions_simplifees)
  win_play = detection_victoire()
  if win_play != "personne":
      GAME_OVER = True
      if win_play == "0":
          win_play = "EGALITE"
      if win_play == "Joueur Jaune" and counter == 0 and menu == False:
          vict_p1 = vict_p1 + 1
      if win_play == "Joueur Rouge" and counter == 0 and menu == False:
          vict_p2 = vict_p2 + 1
      # SI il n'y avait pas la variable counter et menu, le score augmenterait infiniment
#       print(positions_simplifees)
# OUTIL DEBUG


# =========================================================
# == DRAW =================================================
# =========================================================
def draw():
  """création des objets (30 fois par seconde)"""
  global menu, counter, vict_p1, vict_p2, win_play, pos_jetons_r, pos_jetons_j, tour, bottom, GAME_OVER , tour_change , positions_simplifees


# vide la fenetre
  pyxel.cls(0)
  if menu == True:
      pyxel.text(24,24,"menu",5)
      pyxel.text(24, 34, "Victoires J1: "+str(vict_p1), 5)
      pyxel.text(24, 44, "Victoires J2: " + str(vict_p2), 5)
      if pyxel.btnr(KEY_SPACE):
          #FIN DU MENU, INIT DU JEU, RESET DES VARIABLES CLEES
          menu = False
          GAME_OVER = False
          win_play = "personne"
          pos_jetons_j = [[], [],
                          []]  # positions jetons jaunes (j1)   i = 0 pour le placement i = 1 pour quand le jeton tombe (animation) et i = 2 pour la pos definitive
          pos_jetons_r = [[], [],
                          []]  # pos jetons rouges (joueur 2)   i = 0 pour le placement i = 1 pour quand le jeton tombe (animation) et i = 2 pour la pos definitive
          positions_simplifees = [
              [0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0]
          ]  # Simplification par 0 1 ou 2 pour indiquer type de jeton, 0 = vide, 1 = eq 1 et 2 = eq 2


  if menu == False and counter == 30:
      menu = True
      counter = 0
  if counter < 30 and menu == False and GAME_OVER == True:
      counter += 1
      pyxel.text(5, 74, str(win_play) + " gagne la partie", 7)
  if menu == False and counter == 0:
      pyxel.rect(grille_x, grille_y, tableau_width, tableau_hight, 1)


      for i in range(Ligne):
          for j in range(Colone):
              x = grille_x + Dist_X * j + Dist_X // 2
              # y = grille_y + Dist_Y * i + Dist_Y //3 Marche pas
              y = grille_y + Marge_haut + Trou_R + i * Dist_Y
              pyxel.circ(x, y, Trou_R, 0)


      for piece in pos_jetons_j[2]:
          pyxel.circ(piece[0],piece[1],8,10)
      for piece in pos_jetons_j[1]:
          pyxel.circb(piece[0],piece[1],8,10)
      for piece in pos_jetons_j[0]:
          pyxel.circb(piece[0],piece[1],8,10)
      for piece in pos_jetons_r[2]:
          pyxel.circ(piece[0],piece[1],8,4)
      for piece in pos_jetons_r[1]:
          pyxel.circb(piece[0],piece[1],8,4)
      for piece in pos_jetons_r[0]:
          pyxel.circb(piece[0],piece[1],8,4)


pyxel.run(update, draw)