Jeu Ricosheep

Résolu
Bonjour,

Je programme un jeu le Ricosheep. C'est un jeu de type casse-tête, inspiré principalement des jeux Ricochet Robots et 2048. Le jeu se joue sur une grille remplie de moutons, de touffes d’herbe, de buissons et de cases vides et le but du jeu est de placer un mouton sur chaque touffe d’herbe. Le problème, c'est que je dois créer une fonction jouer(plateau,moutons, direction) recevant en paramètre l’état du jeu et une direction représentée par la chaine 'Left', 'Right', 'Up' ou 'Down'. La fonction ne renvoie rien et met directement à jour les positions des moutons dans la liste de tuples,en respectant les règles du jeu. Les moutons se déplacent en groupe dans la direction indiquée jusqu’à rencontrer un obstacle.
J'aimerais avoir un peu d'aide, car je ne sais pas du tout comment faire.

Voici un exemple ci-dessous :



Je vous remercie d'avance.
Configuration: Windows / Chrome 100.0.4896.127

8 réponses

  1. Oui, c'est un projet de cours, mais mon code est assez compliqué (j'aimerais en faire un beaucoup plus simple.) et le problème, c'est que mon programme ne déplace pas plusieurs moutons en même temps et lorsque la direction est 'up' il y a des moutons qui se retrouvent au même endroit qu'un buisson. (alors qu'il ne doit être que sur des cases vides ou sur la touffe d'herbe)
    def detection_moutons_adjacents(moutons,mouton,direction):
        """
        Fonction recevant en paramètre un mouton et une direction vérifiant la présence d'un autre mouton
        sur une case à proximité dans une direction donnée.
        param: moutons : liste de tuple
        param: mouton : tuple
        param: direction : string
        return boolean
    
        >>>detection_moutons_adjacents([(0,4), (1,3), (2,4), (3,4)],(2,4),'Down')
           False
        >>>detection_moutons_adjacents([(0,4), (1,2), (1,4), (3,4)],(1,4),'Left')
           True
        """
        mouton_non_detecte = None
        ligne_mouton = mouton[0]
        colonne_mouton = mouton[1]
        mouton_de_rechange = copy.copy(moutons)
        for dead_mouton in range(len(mouton_de_rechange)) :
            if len(mouton_de_rechange) > dead_mouton :
                if moutons[dead_mouton] in mouton_de_rechange :
                    mouton_de_rechange.pop(dead_mouton)
        if direction == 'Left' :
            for moutons_adjacent in mouton_de_rechange :
                if moutons_adjacent[0] == ligne_mouton :
                    if moutons_adjacent[1] == colonne_mouton-1 :
                        return False
                else :
                    mouton_non_detecte = True
        if direction == 'Right' :
            for moutons_adjacent in mouton_de_rechange :
                if moutons_adjacent[0] == ligne_mouton :           
                    if moutons_adjacent[1] == colonne_mouton+1 :
                        return False
                else :
                    mouton_non_detecte = True        
        if direction == 'Up' :
            for moutons_adjacent in mouton_de_rechange :
                if moutons_adjacent[1] == colonne_mouton :
                    if moutons_adjacent[0] == ligne_mouton-1 :
                        return False
                else :
                    mouton_non_detecte = True
        if direction == 'Down' :
            for moutons_adjacent in mouton_de_rechange :
                if moutons_adjacent[1] == colonne_mouton :
                    if moutons_adjacent[0] == ligne_mouton+1 :
                        return False
                else :
                    mouton_non_detecte = True
        return mouton_non_detecte
    
    
                
    
    def jouer(plateau,moutons,direction):
       
        """
        recevant en paramètre l’état du jeu et une direction représentée par la
        chaine 'Left', 'Right', 'Up' ou 'Down'. La fonction ne renvoie rien et met directement à jour
        les positions des moutons dans la liste moutons en respectant les règles du jeu. 
        param: plateau : list
        param: moutons : list de tuple
        param: direction : string
        """
        for i in range (len(moutons)-1) :
            if direction == 'Left' :
                while moutons[i][1] != 0 and plateau[moutons[i][0]][moutons[i][1]-1] == None :
                    if detection_moutons_adjacents(moutons,moutons[i],'Left'):
                        nouvelle_pos = (moutons[i][0],moutons[i][1]-1)
                        moutons[i] = nouvelle_pos
            if direction == 'Right' :
                while moutons[i][1] != len(plateau[moutons[i][0]])-1 and plateau[moutons[i][0]][moutons[i][1]+1] == None :
                    if detection_moutons_adjacents(moutons,moutons[i],'Right'):
                        nouvelle_pos = (moutons[i][0],moutons[i][1]+1)
                        moutons[i] = nouvelle_pos
            if direction == 'Up' :
                while moutons[i][0] != 0 and plateau[moutons[i][0]-1][moutons[i][1]] == None :
                    if detection_moutons_adjacents(moutons,moutons[i],'Up'):
                        nouvelle_pos = (moutons[i][0]-1,moutons[i][1])
                        moutons[i] = nouvelle_pos
            if direction == 'Down' :
                while moutons[i][0] != len(plateau)-1 and plateau[moutons[i][0]+1][moutons[i][1]] == None :
                    if detection_moutons_adjacents(moutons,moutons[i],'Down'):
                        nouvelle_pos = (moutons[i][0]+1,moutons[i][1])
                        moutons[i] = nouvelle_pos
    1. Tu n'as pas utilisé les balises de code comme te l'explique le lien que je t'ai donné plus haut ...
      1. Ok c'est celle là que tu veux que j'utilise, pas de souci :
        def detection_moutons_adjacents(moutons,mouton,direction):
            """
            Fonction recevant en paramètre un mouton et une direction vérifiant la présence d'un autre mouton
            sur une case à proximité dans une direction donnée.
            param: moutons : liste de tuple
            param: mouton : tuple
            param: direction : string
            return boolean
        
            >>>detection_moutons_adjacents([(0,4), (1,3), (2,4), (3,4)],(2,4),'Down')
               False
            >>>detection_moutons_adjacents([(0,4), (1,2), (1,4), (3,4)],(1,4),'Left')
               True
            """
            mouton_non_detecte = None
            ligne_mouton = mouton[0]
            colonne_mouton = mouton[1]
            mouton_de_rechange = copy.copy(moutons)
            for dead_mouton in range(len(mouton_de_rechange)) :
                if len(mouton_de_rechange) > dead_mouton :
                    if moutons[dead_mouton] in mouton_de_rechange :
                        mouton_de_rechange.pop(dead_mouton)
            if direction == 'Left' :
                for moutons_adjacent in mouton_de_rechange :
                    if moutons_adjacent[0] == ligne_mouton :
                        if moutons_adjacent[1] == colonne_mouton-1 :
                            return False
                    else :
                        mouton_non_detecte = True
            if direction == 'Right' :
                for moutons_adjacent in mouton_de_rechange :
                    if moutons_adjacent[0] == ligne_mouton :           
                        if moutons_adjacent[1] == colonne_mouton+1 :
                            return False
                    else :
                        mouton_non_detecte = True        
            if direction == 'Up' :
                for moutons_adjacent in mouton_de_rechange :
                    if moutons_adjacent[1] == colonne_mouton :
                        if moutons_adjacent[0] == ligne_mouton-1 :
                            return False
                    else :
                        mouton_non_detecte = True
            if direction == 'Down' :
                for moutons_adjacent in mouton_de_rechange :
                    if moutons_adjacent[1] == colonne_mouton :
                        if moutons_adjacent[0] == ligne_mouton+1 :
                            return False
                    else :
                        mouton_non_detecte = True
            return mouton_non_detecte
        
        
                    
        
        def jouer(plateau,moutons,direction):
           
            """
            recevant en paramètre l’état du jeu et une direction représentée par la
            chaine 'Left', 'Right', 'Up' ou 'Down'. La fonction ne renvoie rien et met directement à jour
            les positions des moutons dans la liste moutons en respectant les règles du jeu. 
            param: plateau : list
            param: moutons : list de tuple
            param: direction : string
            """
            for i in range (len(moutons)-1) :
                if direction == 'Left' :
                    while moutons[i][1] != 0 and plateau[moutons[i][0]][moutons[i][1]-1] == None :
                        if detection_moutons_adjacents(moutons,moutons[i],'Left'):
                            nouvelle_pos = (moutons[i][0],moutons[i][1]-1)
                            moutons[i] = nouvelle_pos
                if direction == 'Right' :
                    while moutons[i][1] != len(plateau[moutons[i][0]])-1 and plateau[moutons[i][0]][moutons[i][1]+1] == None :
                        if detection_moutons_adjacents(moutons,moutons[i],'Right'):
                            nouvelle_pos = (moutons[i][0],moutons[i][1]+1)
                            moutons[i] = nouvelle_pos
                if direction == 'Up' :
                    while moutons[i][0] != 0 and plateau[moutons[i][0]-1][moutons[i][1]] == None :
                        if detection_moutons_adjacents(moutons,moutons[i],'Up'):
                            nouvelle_pos = (moutons[i][0]-1,moutons[i][1])
                            moutons[i] = nouvelle_pos
                if direction == 'Down' :
                    while moutons[i][0] != len(plateau)-1 and plateau[moutons[i][0]+1][moutons[i][1]] == None :
                        if detection_moutons_adjacents(moutons,moutons[i],'Down'):
                            nouvelle_pos = (moutons[i][0]+1,moutons[i][1])
                            moutons[i] = nouvelle_pos
        1. Avant tout, je ferais un tableau 2D avec des 0:

          tableau = [[0 for j in range(nb_colonnes)] for i in range(nb_lignes)]


          Ensuite je remplirais avec des 1 si il y a un mouton dans la case, exemple:

          tableau[2][3] = 1


          Pour détecter si il y a des moutons adjacents, je ferais une fonction qui reçoit la position ligne/colonne d'un

          mouton et la direction, et donc qui renvoie True ou False suivant que la case adjacente est libre ou pas
          def case_libre(pos_mouton,dir):
          
              case_libre = False
           
              if(dir == 'right'):
                  case = tableau[pos_mouton[0]][pos_mouton[1]+1]
                  if case == 0: case_libre = True
              elif(dir == 'left'):
          
          #   etc ...
          
              return(case_libre)
          
          print(case_libre([2,2],'right'))
          
          
          1. Modérateur
            Bonjour,

            Comme l'indique Phil, il te faut une structure de donnée qui stocke l'état du plateau, typiquement un tableau 2D (par exemple une liste de listes) dont chaque élément est un entier qui caractérise l'état de la case. On aura donc probablement besoin d'une fonction qui initialise ce plateau de jeu :
            • def init_plateau(num_lignes, num_colonnes)
              ;
            • def get_num_lignes(plateau)
              ;
            • def get_num_colonnes(plateau)
              .


            Il faut d'ailleurs te demander quels sont les états possibles (en l'occurrence une case peut avoir ou non une touffe d'herbe, un mouton, un buisson). Une fois ce choix fait, il serait sans doute pratique d'avoir des fonctions auxiliaires permettant de tester si une case contient ou pas un mouton, une touffe d'herbe, un buisson.
            • def contient_mouton(plateau, i, j)
              ;
            • def contient_buisson(plateau, i, j)
              ;
            • def contient_herbe(plateau, i, j)
              .


            À toi de voir si tu veux que plateau encode la position des moutons, ou si tu préfères que cette information soit mémorisée dans une structure dédiée. La première approche est à mon avis plus simple à coder et la seconde est plus élégante, quoi qu'il en soit les deux approches sont possibles.

            Ces choix faits, on peut commencer à réfléchir à l'algorithme de déplacement. Un mouton se déplace jusqu'à rencontrer un obstacle, qui est soit un buisson, soit un mouton qui ne peut pas se déplacer. Cela suggère que si tu te déplaces disons vers la droite, tu as intérêt à traiter les moutons de la droite vers la gauche. Ainsi, il suffit de tester, au moment de déplacer un mouton, si la case à sa droite est libre (c'est-à-dire ne contient ni mouton, ni buisson) et dans le plateau. Si c'est le cas, le mouton se décale à droite et on répète jusqu'à ce que ce critère d'arrêt soit faux. Puis on passe au mouton suivant.

            Cet algorithme met en évidence que tu as besoin des primitives supplémentaires suivantes (ajouter
            moutons
            si ceux-ci sont stockés dans une structure dédiée) :
            • def est_case_libre(plateau, i, j)
              ;
            • def iter_moutons(plateau, direction)
              ;
            • def deplacer_mouton(plateau, i, j, direction)
              ;


            Bonne chance
        2. Re Bonjour,

          J'ai encore un problème : lorsque la direction est
          'Down'
          , au lieu d'avoir le résultat attendu :

          moutons = [(2, 4), (1, 3), (3, 4), (4, 4)]


          ... les moutons se retrouvent tous au même endroit et j'obtiens :

          moutons = [(4, 4), (1, 3), (4, 4), (4, 4)] 


          Pouvez, vous m'aider s'il vous plait ?

          plateau = [[None, 'B' , None, 'B' , None],
          ['B' , 'B' , None, None, None],
          [None, 'G' , 'B' , 'B' , None],
          [None, 'B' , 'G' , None, None],
          [None, None, None, None , None]]
          
          moutons = [(0, 4), (1, 3), (2, 4), (4, 4)]
          
          def init_plateau(nb_colonnes, nb_lignes):
              tableau = [[0 for j in range(nb_colonnes)] for i in range(nb_lignes)]
              return tableau
          
          def contient_moutons(case,case_moutons,direction):
              if direction == 'Left' or direction == 'Right':
                  pass
             
              if direction == 'Down' or direction == 'Up':
                  if case == None or case  == 'G'  and case_moutons == 0:
                      return True
                  else:
                      return False
              
              
          def jouer(plateau,moutons,direction):
              coord_x = 0
              danger = 0
              plateau_moutons = init_plateau(len(plateau[0]), len(plateau[0]))
              if direction == 'Down':
                  for i in range(len(moutons) - 1, -1, -1):
                      for colonne in range(moutons[i][0], len(plateau[0])):
                          if danger <= 0:
                              if contient_moutons(plateau[colonne][moutons[i][1]], plateau_moutons[colonne][moutons[i][1]], 'Down'):
                                  coord_x = colonne
                              else:
                                  danger += 1
                      moutons[i] = coord_x,moutons[i][1]
                      plateau_moutons[colonne][moutons[i][1]]= 1
                      danger = 0
              if direction == 'Up':
                  for i in range(len(moutons)):
                      for colonne in range(moutons[i][0], -1, -1):
                          if contient_moutons(plateau[colonne][moutons[i][1]],plateau_moutons[colonne][moutons[i][1]], 'Up'):
                              coord_x = colonne
                      moutons[i] = coord_x , moutons[i][1]
                      plateau_moutons[colonne][moutons[i][1]] = 1
              return moutons
          1. Bonjour,
            les couleurs de ton code sont bizarres, tu utilise vraiment les balises Python ?
        3. Modérateur
          Bonjour,

          Pour qu'on soit sûr de comprendre ton code, ce serait pas mal de nous dire ce que signifie
          'B'
          (buisson ?) et (
          'G'
          grass pour herbe ?).

          Ensuite, je pense qu'une direction devrait être définie comme un couple d'entiers
          (di, dj)
          à valeur dans dans {-1, 1} x {-1, 1}. Ainsi, calculer
          (i, j) + (di, dj)
          permet de déterminer la case cible à partir de la case de départ
          (i, j)
          sans se avoir à traiter spécifiquement chaque direction. Ça simplifierait grandement ton code, car tu traiterais d'un coup les 4 directions.

          Bonne chance
          1. Bonjour,

            Bizarre ton dernier code: tu initialise à la fois une variable "plateau" et une variable "tableau"

            Normalement, il s'agit de la même chose, non ?

            Moi, je ferais ça: (je n'ai pas testé si on déborde du plateau dans la fonction premiere_case_vide)

            Et effectivement, on peut balayer les 4 directions en une boucle sans utiliser 'up', 'down', etc ..
            def init_plateau():
            
                plateau = [['V', 'B' , 'V', 'B' , 'V'],
                           ['B' , 'B' , 'V', 'V', 'V'],
                           ['V', 'G' , 'B' , 'B' ,'V'],
                           ['V', 'B' , 'G' , 'V', 'V'],
                           ['V', 'V', 'V', 'V' , 'V']]
            
                return(plateau)
            
            def affiche_plateau(plateau):
            
                for k in range(5):
                    for j in range(5): print(plateau[k][j], end = '  ')
                    print('')
            
            def premiere_case_vide(plateau, pos):
                ''' Retourne la 1ere case adjacente à 'pos' vide'''
            
                liste_dir = [[0,1],[0,-1],[1,0],[-1,0]]
                case_vide = []
            
                for _dir in liste_dir:
                    case = plateau[pos[0]+_dir[0]][pos[1]+_dir[1]]
                    if(case == 'V'):
                        case_vide = [pos[0]+_dir[0],pos[1]+_dir[1]]
                        break
            
                return(case_vide)
            
            plateau = init_plateau()
            affiche_plateau(plateau)
            
            ligne_colonne = [1,1]
            case_vide = premiere_case_vide(plateau, ligne_colonne)
            print('\n1ere case vide adjacente à {} : {}'.format(ligne_colonne, case_vide))