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. 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))
    
    1. 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. 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 ?
      2. 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
      3. 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. Tu n'as pas utilisé les balises de code comme te l'explique le lien que je t'ai donné plus haut ...
          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