Python Dessin ASCII Carte
-
13-12-2019 - |
Question
J'ai besoin d'avoir un rayon de 2 carte tirée du joueur en cours de la chambre de BOUE, je suis en train de construire en python (ou plus si possible).Les chambres sont des conteneurs avec une self.exits = {'west':1, 'north':2}
lorsque la clé est la direction dans laquelle la valeur (UID de la pièce adjacente) est situé.Les chambres sont liés uniquement de cette façon.Un joueur avec une auto.emplacement de 0 pouvaient type " n " et leur emplacement, sur la base de ces variables, pourrait ensuite être 2 et que la salle de contenu aurait du joueur UID ajouté à son contenu.
Donc, je voudrais avoir une carte affichée, qui se présente comme suit, sur la base de ces variables, où le " u " est le joueur de la position actuelle..
[ ]
|
[ ]-[u]
J'ai réalisé cette partie, que c'est juste un rayon de 1.Voici un petit (fortement modifiées pour poster ici) extrait de comment je l'ai fait, et vous allez voir pourquoi je poste, comme c'est le pauvre de code.
mloc = '[u]'
mn = ' '
mw = ' '
spn= ' '
spw= ' '
for Exit in room.exits.keys():
if Exit == 'north':
mn = '[ ]'
spn = '|'
if Exit == 'west':
mw = '[ ]-'
# player.hear() is our function for printing a line to the player's screen
player.hear(' '+mn)
player.hear(' '+sp)
player.hear(mw+mloc)
Dans ma folie, j'ai réussi à faire ce travail avec tous les 8 directions différentes (les diagonales, et ne comprenant pas vers le haut ou vers le bas).Mais j'ai ensuite de boucle pour les chambres j'ai juste analysé avec ma première boucle, puis dessines, et puis l'espace et ensuite prendre en compte le chevauchement de la (sp)des as comme '\' ou '|' si il y a des chemins qui se croisent.Cette petite tâche tourné cauchemardesque immédiatement, et bien en 200 lignes avant j'ai été fait.
Un autre obstacle est que je ne peux impression ligne par ligne.Donc, si la carte est de 50 personnages haut, je dois avoir player.hear()
sur 50 lignes, dont je ne suis pas opposé.Il suffit de garder cela à l'esprit avant de poster une réponse.
Je suis aussi pas pointilleux sur la mise en forme.Je voulez juste simplement une "carte à un coup d'œil" à l'aide des joueurs lors d'un voyage autour du monde.
Merci les gars.J'espère que j'ai fourni suffisamment d'informations.Laissez-moi savoir, si ce n'.(Ici est un lien vers l'intégralité de l' (inachevé et HORRIBLE) module je suis référencement. Map.py
La solution
Ce code est en sérieuse difficulté.Nous allons commencer à concevoir à partir de zéro.Cela devrait servir comme une bonne leçon sur la façon de concevoir et de construire des classes et des structures de données.
Pour commencer, vous devez organiser votre code autour d'un Map
de la classe, qui représente votre chambre comme une grille.Vous ne devez pas penser au sujet de "chambre 1", "chambre 2", etc (ce qui est très difficile de les suivre sur une carte), et pense plutôt à des chambres en termes de coordonnées.
Maintenant, il y a quelques fonctionnalités que nous ignorons au début, y compris le joueur ne voir que des chambres qu'il a été, le joueur restant au centre de la carte, et la diagonale des chemins.Si vous le souhaitez vous pouvez les mettre au plus tard, une fois que les fonctionnalités de base fonctionne.Pour l'instant, nous voulons avoir quelque chose qui ressemble un peu à ceci:
[ ]-[u] [ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
Qui est, nous sommes le représentant comme une grille où certaines chambres sont connectés, et d'autres ne le sont pas.Nous allons avoir dans chaque chambre une paire de coordonnées, un peu comme ceci:
0 1 2 3
0 [ ]-[u] [ ] [ ]
|
1 [ ]-[ ]-[ ] [ ]
|
2 [ ]-[ ]-[ ] [ ]
|
3 [ ]-[ ]-[ ]-[ ]
Soit x le long du haut et y, le long de la côte.Le haut à gauche est (0, 0), l'une avec [u]
dans c'est (0, 1).
Maintenant, quelles sont les composantes de notre Map
de classe?
carte de la hauteur:entier
carte de la largeur:entier)
player_x, player_y:coordonnées de joueur
les chemins d'accès possibles:une liste de paires de chambres que l'on peut déplacer entre.La carte ci-dessus est représenté sous la forme:
[((0, 0), (1, 0)), ((0, 0), (1, 0)), ((1, 0), (1, 1)), ((1, 1), (2, 1)), ((1, 0), (1, 2)), ((0, 2), (1, 2)), ((1, 2), (2, 2)), ((0, 2), (0, 3)), ((0, 3), (1, 3)), ((1, 3), (2, 3)), ((2, 3), (3, 3))]
Notez que j'ai commandé chaque paire telle que le plus grand tuple va d'abord (c'est important plus tard).
Alors, maintenant que nous avons notre conception, nous allons écrire que Map
la classe!
Je ne peux penser à de quatre méthodes que nous voulons: print_map
, move
, et un initialiseur.Intitialization est simple:il suffit de régler le quatre attributs que nous avons énumérés ci-dessus:
class Map:
def __init__(self, height, width, player_x, player_y, paths):
self.height = height
self.width = width
self.x = player_x
self.y = player_y
self.paths = paths
Maintenant, move
est assez simple.Donné une direction n/e/s/w:
def move(self, direction):
if direction == "n":
if ((self.x, self.y - 1), (self.x, self.y)) not in self.paths:
print "Cannot go north"
else:
self.y -= 1
L' move
la fonction de "nord" vérifie juste si il y a un chemin d'accès à la salle au-dessus de la nôtre.
Maintenant pour la partie la plus intéressante:l'impression de la carte.Pour ce faire, vous passez en boucle sur les lignes (de 0 à self.height
) et sur les colonnes (de 0 à self.width
). (Note:vous ne pouvez pas utiliser print
dans cette situation, car il met automatiquement un saut de ligne ou un espace après la chaîne.Au lieu de cela, nous utilisons sys.la sortie standard stdout.écrire.
def print_map(self):
for y in range(0, self.height):
# print the yth row of rooms
for x in range(0, self.width):
if self.x == x and self.y == y:
sys.stdout.write("[u]") # this is the player's room
else:
sys.stdout.write("[ ]") # empty room
# now see whether there's a path to the next room
if ((x, y), (x + 1, y)) in self.paths:
sys.stdout.write("-")
else:
sys.stdout.write(" ")
# now that we've written the rooms, draw paths to next row
print # newline
for x in range(0, self.width):
sys.stdout.write(" ") # spaces for above room
if ((x, y), (x, y + 1)) in self.paths:
sys.stdout.write("| ")
else:
sys.stdout.write(" ")
print
Maintenant, nous allons mettre tout cela ensemble et de l'essayer.Voici le code:
import sys
class Map:
def __init__(self, height, width, player_x, player_y, paths):
self.height = height
self.width = width
self.x = player_x
self.y = player_y
self.paths = paths
def move(self, direction):
if direction == "n":
if ((self.x, self.y - 1), (self.x, self.y)) not in self.paths:
print "Cannot go north"
else:
self.y -= 1
if direction == "s":
if ((self.x, self.y), (self.x, self.y + 1)) not in self.paths:
print "Cannot go south"
else:
self.y += 1
if direction == "e":
if ((self.x, self.y), (self.x + 1, self.y)) not in self.paths:
print "Cannot go east"
else:
self.x += 1
if direction == "w":
if ((self.x - 1, self.y), (self.x, self.y)) not in self.paths:
print "Cannot go west"
else:
self.x -= 1
def print_map(self):
for y in range(0, self.height):
# print the yth row of rooms
for x in range(0, self.width):
if self.x == x and self.y == y:
sys.stdout.write("[u]") # this is the player's room
else:
sys.stdout.write("[ ]") # empty room
# now see whether there's a path to the next room
if ((x, y), (x + 1, y)) in self.paths:
sys.stdout.write("-")
else:
sys.stdout.write(" ")
# now that we've written the rooms, draw paths to next row
print # newline
for x in range(0, self.width):
sys.stdout.write(" ") # spaces for above room
if ((x, y), (x, y + 1)) in self.paths:
sys.stdout.write("| ")
else:
sys.stdout.write(" ")
print
paths = [((0, 0), (1, 0)), ((0, 0), (1, 0)), ((1, 0), (1, 1)), ((1, 1),
(2, 1)), ((1, 1), (1, 2)), ((0, 2), (1, 2)), ((1, 2), (2, 2)),
((0, 2), (0, 3)), ((0, 3), (1, 3)), ((1, 3), (2, 3)), ((2, 3),
(3, 3))]
m = Map(4, 4, 0, 0, paths)
while True:
m.print_map()
direction = raw_input("What direction do you want to move? [n/e/s/w] ")
m.move(direction)
Notez que j'ai ajouté une section sur le fond qui crée une carte et permet au joueur de se déplacer autour d'elle.Voici à quoi il ressemble quand il s'exécute:
Davids-MacBook-Air:test dgrtwo$ python Map.py
[u]-[ ] [ ] [ ]
|
[ ] [ ]-[ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
What direction do you want to move? [n/e/s/w] e
[ ]-[u] [ ] [ ]
|
[ ] [ ]-[ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
What direction do you want to move? [n/e/s/w] s
[ ]-[ ] [ ] [ ]
|
[ ] [u]-[ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
What direction do you want to move? [n/e/s/w] w
Cannot go west
[ ]-[ ] [ ] [ ]
|
[ ] [u]-[ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
What direction do you want to move? [n/e/s/w] e
[ ]-[ ] [ ] [ ]
|
[ ] [ ]-[u] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
Il y a beaucoup d'améliorations qui peuvent être apportées à ce code (en particulier, l' move
la méthode est répétitif), mais c'est un bon début.Essayez de faire la carte de 20x20 et vous verrez qu'il se développe très bien.
ETA:Il est à noter que print_map
pourrait être réécrit dans un temps beaucoup plus court formulaire comme quelque chose comme:
def print_map(self):
for y in range(0, self.height):
print "".join(["[%s]%s" %
("u" if self.x == x and self.y == y else " ",
"-" if ((x, y), (x + 1, y)) in self.paths else " ")
for x in range(0, self.width)])
print " " + " ".join(["|" if ((x, y), (x, y + 1)) in self.paths
else " " for x in range(0, self.width)])
Mais c'est un peu plus intense.
Autres conseils
J'ai fait cela comme un exercice où les chambres et la grille "imprimer eux-mêmes".J'ai ajouter à la discussion comme il peut être plus facile à mettre en œuvre avec un éventuel réseau plus large.
L'ASCII Carte
+++++++++++++++
+++++++++++++++
+++++++++++++++
++++++ ++++++
++++++ 2 ++++++
++++++/| ++++++
+++ / | ++++++
+++ 3--1 ++++++
+++ \++++++
+++++++++\ +++
+++++++++ 4 +++
+++++++++ +++
+++++++++++++++
+++++++++++++++
+++++++++++++++
Chaque cellule de cette grille de trois par trois de '+' signes.Quatre chambres sont mis en œuvre avec la valeur de l'id de 1 à 4.Les connexions entre les chambres sont représentés comme des barres obliques inverses et des tuyaux.
Le Code
class Room(object):
def __init__(self, id, loc, exits):
self.id = id # unique identifier, may be a name
self.row = loc[0] # loc is tuple of (row, col)
self.col = loc[1]
# exits is a list where 'X' means no exit and
# any other value is id of destination
self.exits = exits
def __str__(self):
directions = '\\|/- -/|\\'
room = [ e if e == 'X' else ' ' for e in self.exits ]
for idx in range(len(room)):
if room[idx] == ' ':
room[idx] = directions[idx]
if room[idx] == 'X':
room[idx] = ' '
room[4] = self.id[0] # only print first char of id
return ''.join(room)
class Map(object):
def __init__(self, rows, cols, rooms):
self.rows = rows
self.cols = cols
self.rooms = rooms
def __str__(self):
world = []
for i in range(self.rows * 3):
world.append( ['+++'] * self.cols )
for room in self.rooms:
ascii = str(room)
x = room.col
y = room.row
for idx in range(0, 3):
cell = ascii[idx*3:idx*3+3]
world[y*3+idx][x] = cell
return '\n'.join( [ ''.join(row) for row in world ] )
if __name__ == '__main__':
# set up four rooms
# each room has unique id (string of any length) and coordinates
# it also has a set of 8 possible exits, represented as a list where
# 'X' means exit is blocked and valid exits contain the id of the target room
r1 = Room(id='1', loc=(2,2), exits=['X','2','X',
'3',' ','X',
'X','X','4',])
r2 = Room(id='2', loc=(1,2), exits=['X','X','X',
'X',' ','X',
'3','1','X',])
r3 = Room(id='3', loc=(2,1), exits=['X','X','2',
'X',' ','1',
'X','X','X',])
r4 = Room(id='4', loc=(3,3), exits=['1','X','X',
'X',' ','X',
'X','X','X',])
# initialize Map with a list of these four rooms
map = Map(rows = 5, cols=5, rooms=[r1, r2, r3, r4])
print map
Le déplacement de routine n'est pas mis en œuvre, et pour cette représentation au travail, à caractère unique id va se montrer bien.
Les avantages de ce système:
- facile d'ajouter des chambres et de les supprimer
- la définition d'une chambre est lisible par l'homme
- les fonctions de sortie surcharge
__str__
et, partant, des chambres et de la grille "imprimer eux-mêmes" et cela pourrait être utile pour l'avenir de débogage ou d'adaptation à de futurs formats par exemplecomme les cellules dans un tableau HTML.
Coordonner les cartes ont beaucoup d'avantages, mais vu que beaucoup de la qualité des boues d'utiliser une chambre traditionnelle à base de monde, et les gens ont fait automappers pour beaucoup de boue et de la boue de clients, il n'est pas hors de question de faire un automap pour une boue sans coordonnées.Vous aurez juste à faire face à des conflits sur une base de cas par cas.
Cependant, vous pouvez toujours utiliser la réponse par @david-robinson.Ce que vous voulez faire est de garder une minicarte à peu près centrée sur le joueur et mettre à jour dynamiquement à l'aide de la sortie des données.N'essayez pas de garder une carte de l'ensemble de la zone de conservation;par une mise à jour dynamique vous permettra d'éviter certains géographique des conflits.
Pour l'écriture de la carte pour une boue client, tout ce que vous devez faire est d'écrire votre carte en ligne correctement espacés et terminer par une nouvelle ligne.Vous mettez tous la carte des lignes dans une liste afin d'être envoyé en un seul groupe de lignes (vous ne voulez pas que d'autres inséré entre les lignes de la carte par exemple lorsqu'on a envoyé la prise), et toute la boue client de l'imprimer correctement (avec une police à espacement fixe, bien sûr).