Python Disegno ASCII Mappa
-
13-12-2019 - |
Domanda
Ho bisogno di avere un 2 raggio mappa disegnata spegnere il lettore attuale stanza in un FANGO sto costruendo in python (o più, se possibile).Le camere sono come contenitori con un self.exits = {'west':1, 'north':2}
dove la chiave è la direzione che il valore (UID della stanza adiacente) è situato.Le camere sono collegate solo in questo modo.Un giocatore con un auto.posizione di 0 potrebbe digitare " n " e la loro posizione, sulla base di quanto sopra variabile, sarebbe di 2 e che il contenuto della stanza sarebbe il giocatore UID aggiunto al suo contenuto.
Così, mi piacerebbe avere una mappa che appare come il seguente, in base alla suddetta variabile, dove la 'u' è il giocatore della posizione corrente..
[ ]
|
[ ]-[u]
Ho realizzato questo parte, come questo è solo un raggio di 1.Ecco un piccolo (pesantemente modificato per postare qui) frammento di come ho fatto questo, e vedrete perché sto postando, come è povero di codice.
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)
Nella mia follia, sono riuscito a fare questo lavoro con tutte le 8 direzioni diverse (diagonali, e non in alto o in basso).Ma poi devo ciclo for sale ho appena analizzato con il mio primo ciclo for, e quindi disegnare quelle, e poi spazio del tutto, e poi prendere in considerazione la sovrapposizione di (sp)assi come '\' o '|' se ci sono percorsi che si incrociano.Questo è un piccolo compito trasformato da incubo immediatamente, e in 200 righe prima che mi è stato fatto.
Un altro ostacolo è che posso stampare solo una riga alla volta.Quindi, se la mappa è di 50 caratteri alta, devo player.hear()
a 50 linee, che io non mi oppongo a.Basta tenere a mente prima di postare una risposta.
Io non sono schizzinosi riguardo la formattazione.Ho semplicemente una "mappa a colpo d'occhio" per aiutare i giocatori durante il viaggio intorno al mondo.
Grazie ragazzi.Spero che vi ho fornito abbastanza informazioni.Fammi sapere, se non.(Ecco un link per l'intero (incompiuto e ORRIBILE) modulo mi sto riferendo. Map.py
Soluzione
Questo codice è in guai seri.Iniziamo a progettare da zero.Questo potrà servire come una buona lezione su come progettare e costruire classi e strutture di dati.
Per cominciare, si dovrebbe organizzare il tuo codice intorno a un Map
classe, che rappresenta quindi il sale, come una griglia.Non si deve pensare a "camera 1", "camera 2", ecc (che è molto difficile tenere traccia di una mappa), e invece penso di camere, in termini di coordinate.
Ora, ci sono alcuni possibili funzioni che siamo ignorando all'inizio, tra cui il lettore di vedere solo le camere è stato a, il giocatore rimane al centro della mappa, e di percorsi diagonali.Se vuoi li puoi mettere, in seguito, una volta che la funzionalità di base funziona.Per ora, stiamo puntando a qualcosa che assomiglia un po ' a questo:
[ ]-[u] [ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
Che è, siamo, presentandola come una griglia in cui alcune camere sono comunicanti e altri non lo sono.Facciamo ogni camera dispone di una coppia di coordinate, un po ' come questo:
0 1 2 3
0 [ ]-[u] [ ] [ ]
|
1 [ ]-[ ]-[ ] [ ]
|
2 [ ]-[ ]-[ ] [ ]
|
3 [ ]-[ ]-[ ]-[ ]
Sia x lungo la parte superiore e y lungo il lato.In alto a sinistra è (0, 0), l'uno con [u]
in esso è (0, 1).
Ora, quali sono le componenti del nostro Map
classe?
mappa di altezza:integer
mappa larghezza:integer)
player_x, player_y:coordinate del giocatore
possibili percorsi:un elenco di coppie di camere che ci si può spostare tra.Sopra la mappa dovrebbe essere rappresentato come:
[((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))]
Notare che ho ordinato ogni coppia tale che il più grande tupla va per primo (che è importante).
Quindi, ora che abbiamo il nostro design, scriviamo Map
di classe!
Posso pensare di quattro metodi vogliamo: print_map
, move
, e un inizializzatore.Intitialization è semplice:basta impostare i quattro attributi elencati sopra:
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
Ora, move
è abbastanza semplice.Dato una direzione 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
Il move
funzione per il "nord" e controlla se c'è un percorso per la stanza successiva a quella in cui ci troviamo.
Ora per la parte più interessante:stampa la mappa.Questo dal ciclo sulle righe (da 0 a self.height
) e oltre le colonne (da 0 a self.width
). (Nota:non è possibile utilizzare print
in questa situazione, dal momento che si inserisce automaticamente una nuova riga o spazio dopo la stringa.Invece usiamo sys.stdout.scrivere.
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
Ora, mettiamo tutto insieme e provare.Ecco il codice:
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)
Notare che ho aggiunto una sezione in basso, che crea una mappa e permette al giocatore di muoversi.Ecco come appare quando viene eseguito:
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] [ ]
|
[ ]-[ ]-[ ] [ ]
|
[ ]-[ ]-[ ]-[ ]
Ci sono molti miglioramenti che possono essere fatte a questo codice (in particolare, il move
il metodo è ripetitivo), ma è un buon inizio.Provare a fare una mappa di 20x20 e vedrai che si espande bene.
ETA:Devo notare che print_map
potrebbe essere riscritto in tempi molto più brevi forma come qualcosa di simile a:
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)])
Ma questo è un po ' più intenso.
Altri suggerimenti
L'ho fatto come un esercizio in cui le stanze e la griglia "stampano se stesse".Aggiungo questo alla discussione in quanto potrebbe essere più facile da implementare con un'eventuale griglia più grande.
La mappa ASCII
+++++++++++++++
+++++++++++++++
+++++++++++++++
++++++ ++++++
++++++ 2 ++++++
++++++/| ++++++
+++ / | ++++++
+++ 3--1 ++++++
+++ \++++++
+++++++++\ +++
+++++++++ 4 +++
+++++++++ +++
+++++++++++++++
+++++++++++++++
+++++++++++++++
.
Ogni cella in questa griglia è un tre di tre serie di segni "+".Quattro camere sono implementate con valore ID da 1 a 4. Le connessioni tra le camere sono rappresentate come barrette, backslash e tubi.
il codice
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
.
La routine in movimento non è implementata, e per questa rappresentazione funziona, solo gli ID di caratteri singoli verranno visualizzati piacevolmente.
I vantaggi di questo sistema:
- .
- Facile da aggiungere camere e rimuoverli
- La definizione di una stanza è leggibile dall'uomo
- Le funzioni di uscita sovraccaricano generacodictagcode e quindi le stanze e la griglia "Stampa se stesse" e questo potrebbe essere utile per il futuro debug o adattamento ai formati futuri ad es.come cellule in una tabella HTML.
Le mappe a base di coordinate hanno molti vantaggi, ma considerando che molti fanghi di qualità usano un tradizionale mondo della stanza, e le persone hanno reso le automobili per molti fanghi e clienti di fango, non è fuori questione per creare un Automap per A fango senza coordinati. Dovrai solo affrontare i conflitti in caso per caso.
Tuttavia, puoi ancora usare la risposta di @ David-Robinson. Quello che vuoi fare è mantenere una minimaata incidentale centrata sul lettore e aggiornando dinamicamente utilizzando i dati di uscita. Non cercare di tenere una mappa dell'intera area memorizzata; Aggiornamento dinamico avrai evitato alcuni conflitti geografici.
Per scrivere la mappa a un client di fango, tutto ciò che devi fare è scrivere la tua linea mappa correttamente distanziata e terminarla con una nuova riga. Metti tutte le linee della mappa in un elenco in modo che venga inviato come un singolo gruppo di righe (non vuoi un'altra linea inserita tra linee della mappa ad esempio quando viene inviata la presa), e qualsiasi client di fango lo stampa correttamente (con un font monospaziale ovviamente).