J'ai compris:
a.append(i[:i.find("o")] + " " +"o"+ i[i.find("o")+2:])
j'ai besoin du "o" pour en déplacer un vers la droite
state = ( "##### ", "### #", "## o##", " #####" )
à
def move(state, direction): for indx,i in enumerate(state): if "o" in i: line_indx= indx string_indx = state[line_indx].find("o") print(line_indx,string_indx) a=[] if direction.lower() == "rechts" and state[line_indx][string_indx+1] == " ": print("that would work") for i in state: if "o" not in i: a.append(i) elif "o" in i: a.append(i[:i.find("o")] + " o" + i[i.find("o")+1:])
le fait est qu'il doit être vraiment robuste pour les cas de pointe comme:
"o ##"
J'ai codé comme ça mais ça ne fonctionnera pas comme ça ...
"## o##"
Je dois me débarrasser de ce truc de tranchage mais je ne sais pas comment ...
Merci d'avance!!
EDIT: la sortie devrait ressembler à ceci
"## o ##"
E2:
state = ( "##### ", "### #", "## o ##", " #####" )
fonctionne mais il doit y avoir une meilleure solution ...
4 Réponses :
si vous voulez que "## o #" soit converti en "## o #" voici le code. En supposant que "état" est une liste comme vous l'avez mentionné "liste" dans la question
for indx,i in enumerate(state): if "o " in i: line_indx= indx state[indx]=i.replace("o ","o") print(state)
state
est clairement un tuple. Comme les tuples sont immuables, votre solution ne fonctionnera pas. D'où avez-vous également obtenu la variable l
?
je l'ai édité. La liste était mentionnée dans la question
J'utiliserais re
module pour la manière suivante:
('##### ', '### #', '## o##', ' #####')
Production:
import re state = ( "##### ", "### #", "## o ##", " #####" ) new_state = tuple(re.sub(r"(o)(\s)", r"\2\1", i) for i in state) print(new_state)
Notez que cela permutera chaque o
avec un espace à sa droite, pour chaque o
qui a un espace à sa droite. Explication: J'ai utilisé ce que l'on appelle des groupes de capture et des références pour eux.
fou, merci beaucoup !! pouvez-vous m'expliquer les choses à l'intérieur du re.sub () ou m'envoyer un lien avec des explications? Je dois le faire pour différents cas également (déplacement vers la gauche par exemple)
@Orsons: Je suggère d'abord de lire la documentation re.sub , puis d'utiliser regex101 pour comprendre ce modèle particulier
Je dirais que le moyen le plus simple de résoudre ce problème est de vérifier pour chaque ligne si elle contient un «o». Si c'est le cas, vous voulez que la ligne soit tout avant le 'o' ( line[0:idx]
), alors le 'o' précédé d'un espace ( " o"
) et puis tout après le 'o', en tenant compte du espace nouvellement ajouté ( line[idx + 2:]
).
... if 'o' in line: idx = line.find('o') line = left(line, idx) ...
Cela donnera la sortie:
def left(line, idx): return line[0:idx - 1] + "o " + line[idx + 1:] def right(line, idx): return line[0:idx] + " o" + line[idx + 2:]
ÉDITER
Je vois dans un commentaire que vous voulez également pouvoir vous déplacer vers la gauche, etc. Dans ce cas, vous pouvez remplacer le contenu de l'instruction if par un appel de fonction qui traite la ligne en conséquence, c'est-à-dire:
('##### ', '### #', '## o##', ' #####')
Et puis à l'intérieur de la boucle:
state = ( "##### ", "### #", "## o ##", " #####" ) newstate = [] for line in state: if 'o' in line: idx = line.find('o') line = line[0:idx] + " o" + line[idx + 2:] newstate.append(line) state = tuple(newstate) print(state)
En supposant que vous vouliez pouvoir vous déplacer dans les quatre directions et pas seulement vers la droite. À mon avis, il est plus facile de travailler avec des séquences mutables pour de tels types de problèmes (comme Thomas l'a suggéré). Ie utilise une List
imbriquée comme état au lieu du tuple
immuable de str
s. Si vous ne parvenez pas à modifier la signature de la fonction, vous pouvez utiliser des casts de type comme ceci:
def test_move_right(): state = ( "##### ", "### #", "## o ##", " #####" ) expected_state = ( "##### ", "### #", "## o##", " #####" ) new_state = move(state, Direction.right) assert new_state == expected_state def test_move_right_blocked(): state = ( "##### ", "### #", "## o##", " #####" ) with pytest.raises(AssertionError): move(state, Direction.right) def test_move_right_out(): state = ( "##### o", "### #", "## ##", " #####" ) with pytest.raises(AssertionError): move(state, Direction.right)
Testez les hypothèses suivantes:
).#
.Vous devriez également vérifier les autres cas extrêmes.
import typing as t from enum import Enum State = t.Tuple[str, ...] Position = t.Tuple[int, int] class Direction(str, Enum): up = "up" down = "down" left = "left" right = "right" def get_position(state: State) -> Position: o_indices = [(x, y) for x, row in enumerate(state) for y, item in enumerate(row) if item == "o"] assert len(o_indices) == 1, "There must be exactly one o." return o_indices[0] def move(state: State, direction: Direction) -> State: x, y = old_x, old_y = get_position(state) if direction == "down": x += 1 elif direction == "up": x -= 1 elif direction == "right": y += 1 elif direction == "left": y -= 1 # Assert validity of move: assert 0 <= x < len(state), "Trying to move out of field vertically." assert 0 <= y < len(state[0]), "Trying to move out of field horizontally." assert state[x][y] != "#", "Trying to move into fence." # This would be easier with a MutableSequence, i.e. if state was a nested List new_state = list(list(row) for row in state) new_state[x][y] = "o" new_state[old_x][old_y] = " " return tuple("".join(row) for row in new_state)
Merci pour votre réponse détaillée! Cela m'a beaucoup aidé, j'ai juste oublié de voter ... désolé
Les chaînes et les tuples sont immuables en Python. Pouvez-vous plutôt représenter l'État sous forme de liste de listes? Ensuite, vous pouvez facilement attribuer des éléments individuels.