Porttasin aiemman koodivinkin pythonille, koska täällä ei ole kovin montaa python vinkkiä.
Toimintaperiaate:
"Joka tapauksessa idea menee siten, että merkataan kaikki lähtöpisteen ympärillä olevat ruudut
(ei kuitenkaan seiniä ja muita esteitä) yhtä suuremmalla, kuin lähtöpiste. Sitten käydään karttaa
läpi etsien äsken merkattuja ruutuja ja merkataan niiden ympärillä olevat ruudut (ei seiniä, esteitä eikä jo merkattuja ruutuja).
Tätä jatketaan, kunnes tullaan päätepisteeseen.
Sitten lähdetään tulemaan takaisin päin. Etsitään päätepisteen ympäriltä pienimmällä arvolla merkattu ruutu ja kirjataan reitin piste ylös,
sitten etsitään tämän uuden pisteen ympäriltä pienintä arvoa vastaava ruutu ja jatketaan näin, kunnes tullaan ruutuun jonka vastaava arvo on 1, eli ruutu on yhden päässä aloituspisteestä ja reitti on valmis.
Ja kuten huomanette, algorithmi olettaa, että kaikki kuljettava alue on yhtä helppokulkuista.""
- kimbledon muokkasi tekstiä hieman, alkuperäinen löytyy linkistä.
- Kirjoittaja: Gaxx (20.11.2005) https://www.ohjelmointiputka.net/koodivinkit/24841-cpp-lyhimmän-reitin-etsiminen
Kartta voisi olla tämän näköinen:
S 0 1 F
0 1 1 0
0 1 0 0
0 0 0 0
Jolloin ensimmäinen ruutu(S) vastaisi koordinaateiltaan pistettä (1,1)
Päätepiste(F) taas vastaisi pistettä (4,1)
Koordinaatit ovat siis muotoa (X,Y) josta X,Y € Z+ eli X ja Y voivat olla vain positiivisia kokonaislukuja
0 vastaa kulkukelpoista aluetta(jonka voi määritellä alempana listassa
1 vastaa estettä josta ei voi kulkea(myös voi määritellä)
Kartalla voi liikkua jokaiseen suuntaan ja MYÖS vinottaiset suunnat vastaavat yhden yksikön siirtymää jolloin suoralla reitillä
on sama mennäänkö siksakkia vai täysin suoraan, esimerkki:
Kuitenkin ohjelma yrittää ensin etsiä ensin reittiä missä ei tarvitse mennä vinottain, jotta saataisiin siistimpi reitti.
HUOM! Ohjelman voi halutessaan muuttaa niin, ettei kartalla voi mennä vinottain eli voi liikkua vain neljään suuntaan.
Se onnistuu muuttamalla lyhyin() funktion kutsun viimeistä parametriä, se on oletuksena 1, se pitää vaihtaa: 0
Ohje ajamiseen:
Tallenna koodit omiin tiedostoihinsa ylempi nimellä routefuncs.py ja alempi nimellä route.py.
Tämän jälkeen lataa http://tauri.nikkeli.net/kartta.txt ja tallenna se samaan kansioon, jonka jälkeen aja route.py.
Komentoriviltä: python route.py (karttatiedosto.txt)
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# routefuncs.py - reitin laskemisen funktiot
import random
# Palauttaa yhden pisteen perustella sen viereiset pisteet joihin VOIDAAN liikkua
def karsilahimmat(p, maplist, loppu, vapaat, vinottain=1, valmiit=[]):
if vinottain: # Pisteen kaikki viereiset pisteet
plist = [(p[0]+1,p[1]),(p[0],p[1]+1),(p[0]+1,p[1]+1),(p[0]-1,p[1]),(p[0],p[1]-1),(p[0]-1,p[1]-1),(p[0]+1,p[1]-1),(p[0]-1,p[1]+1)]
else: # Pisteen kaikki viereiset pisteet(ei vinosuuntiin)
plist = [(p[0]+1,p[1]),(p[0],p[1]+1),(p[0]-1,p[1]),(p[0],p[1]-1)]
nplist = [] # Uusi lista johon lisätään vain kelvolliset pisteet
y_len = len(maplist)+1 # y:n arvon on AINA oltava pienempi kuin tämä
for p in plist:
if p[1] > 0 and p[1] < y_len: # Pitää olla positiivinen luku ja ei saa ylittää karttaa( Y KOORDINAATTI )
# Pitää olla positiivinen ja ei saa ylittää karttaa(X KOORDINAATTI)
if p[0] > 0 and p[0] < len(maplist[p[1]-1])+1:
# Pistettä vastaavan merkin pitää olla kulkukelpoista aluetta
if p2merkki(p,maplist) in vapaat:
# Varmistetaan ettei merkata jo merkattuja!
if p not in valmiit:
nplist.append(p)
if p == loppu: nplist.append(p) # Jos piste on päätepiste niin lisätään se varmasti
return nplist
def p2merkki(p, maplist): # maplist on normaali lista(nmap, jossa ei ole välejä)
return maplist[p[1]-1][p[0]-1] # Palautetaan kartalta pisteen koordinaatteja vastaavan merkin
def isvino(p1,p2): # Voit käyttää VAIN vierekkäisten pisteiden tapauksessa
if p1[0] != p2[0] and p1[1] != p2[1]: return 1
else: return 0
def getstart(maplist,aloitus): # Hakee kartasta aloituspisteen koordinaatit
o = 0
for f in maplist:
if aloitus in f:
return (f.rfind(aloitus)+1,o+1)
o += 1
return -1
def getend(maplist,lopetus): # Hakee kartasta lopetuspisteen koordinaatit
o = 0
for f in maplist:
if lopetus in f:
return (f.rfind(lopetus)+1,o+1)
o += 1
return -1
# Tästä alkaa reitin etsintä!
def lyhyin(kartta,map_aloitus,map_lopetus,vapaat,esteet,vinottain=1):
# Kartassa ei ole aloitusta tai lopetusta
if map_aloitus not in ''.join(kartta) or map_lopetus not in ''.join(kartta): return -2
arvot = {} # Sanakirjaan tulee pisteitä vastaavat arvot
loppupiste = getend(kartta,map_lopetus)# Haetaan loppupisteen koordinaatit
# Haetaan alkupisteestä seuraavat mahdolliset reitin jatkopisteet
edelliset = karsilahimmat(getstart(kartta,map_aloitus),kartta,loppupiste,vapaat,vinottain)
i = 1
for p in edelliset: arvot[p] = i # Merkataan niille kaikille arvoksi 1
if getend(kartta,map_lopetus) in arvot: return [loppupiste]
# Lisätään pisteitä ja niiden arvoja sanakirjaan niin kauan kunnes on loppupiste löydetään
while loppupiste not in arvot:
i += 1
uudet = []
# Käydään viimekerralla löydetyt pisteet läpi ja etsitään jokaiselle niille uudet jatkopisteet
for p in edelliset:
for u in karsilahimmat(p,kartta,loppupiste,vapaat,vinottain,arvot.keys()+uudet):
uudet.append(u)
if uudet == []: return -1 # Reitti ei ole mahdollinen
edelliset = uudet[:] # Kopioidaan ne edellisiin, jotta ne jää talteen
for p in uudet: arvot[p] = i # Merkataan taas uusille pisteille niiden arvot
reitti = []
done = 0
i = 0
while not done: # Sitten jatketaan pienimpien arvojen etsimistä
i += 1
if i != 1: viim_piste = reitti[-1]
else: viim_piste = loppupiste
# Karsitaan taas viimeisimmän pisteen perusteella kulkukelpoiset pisteet
mahd_pisteet = karsilahimmat(viim_piste,kartta,loppupiste,vapaat,vinottain)
# Selvitetään, mikä on pienin arvo
pieninarvo = 0
for p in mahd_pisteet:# Muodostetaan lista pisteitä vastaavista ARVOISTA
if pieninarvo == 0:
if p in arvot: pieninarvo = arvot[p]
else:
if p in arvot:
if arvot[p] < pieninarvo: pieninarvo = arvot[p]
if not vinottain:
for piste,arvo in arvot.items():
# Etsitään taas pieniarvoisin piste, jonka täytyy myös olla mahd_pisteet-listassa
if arvo == pieninarvo and piste in mahd_pisteet:
reitti.append(piste) # Lisätään se reittiin
if arvo == 1: # Jos olemme jo yhden päässä aloituspisteestä, lopetetaan.
done = 1
break
else:
suora = 0
kelvolliset = []
for piste,arvo in arvot.items():
# Jos sanakirjasta löydettiin arvo joka vastaa pienintä
if arvo == pieninarvo and piste in mahd_pisteet:
# Lisätään lahimmat listaan piste joka on kelvollinen seuraava askel
kelvolliset.append(piste)
if arvo == 1: # Reitti on valmis!
done = 1
# Suositaan pisteitä, joihin ei tarvitse liikkua vinottain
if not isvino(viim_piste,piste):
reitti.append(piste) # Lisätään piste reittilistaan
suora = 1 # Löydettiin suorakin siirtymä, joten ei arvota vinottaista
break
if not suora: # Jos ei löydetty suoraa siirtymää, niin arvotaan seuraava askel
reitti.append(random.choice(kelvolliset)) # Erotetaan reitin pisteet x:llä
return reitti#!/usr/bin/python # -*- coding: UTF-8 -*- # route.py - lyhyimmän reitin laskija import sys from routefuncs import * if len(sys.argv) == 2: # Tiedosto annettiin parametrinä map_tiedosto = sys.argv[1] else: map_tiedosto = 'kartta.txt' # Tiedosto, josta luetaan kartta map_aloitus = 'S' # Karttan merkitty päätepiste map_lopetus = 'F' # Karttaan merkitty aloituspiste nmap_vapaat = ['0'] # Kartassa olevat liikkumakelpoiset merkit nmap_esteet = ['1'] # Kartassa olevat esteet emap_este = '#' # Kun kartta tulostetaan niin kaikki esteet merkataan selvyyden vuoksi tällä merkillä # Merkkaa kartan reunat siististi def reunusta(teksti,u='|',d='-'): ulist = [' '*len(u)+d*len(teksti[0])] i = 0 k = 0 for x in teksti: if i == len(teksti)-1: ulist.append(u+x+u) elif len(x) < len(teksti[i+1]): pituus = len(teksti[i+1])-len(x) if pituus < 0: pituus *= -1 ulist.append(u+x+' '+(d*(pituus-1))) elif len(x) > len(teksti[i+1]): ulist.append(u+x+u) pituus = len(x)-len(teksti[i+1]) if pituus < 0: pituus *= -1 print pituus k = 1 elif k==1: k = 0 ulist.append(u+teksti[i]+' '+(d*(pituus-1))) else: ulist.append(u+x+u) i += 1 return ulist+[' '*len(u)+d*len(teksti[-1])] def map2vmap(nmap): # Muuttaa kartan jossa ei ole joka toinen kirjain väli, sellaiseksi jossa joka toinen on väli(kartta.txt) vmap = [] for f in nmap: line = '' for k in f: line = line+' '+k vmap.append(line[1:]) return vmap def vmap2map(vmap): # Poistetaan kartasta välilyöntimerkit nmap = [] for f in vmap: nmap.append(f[::2]) # Joka toinen kirjain return nmap def nmap2emap(nmap): # Muutetaan normaalimuotoinen kartta sellaiseksi jonka voi tulostaa emap = [] for f in nmap: line = '' for k in f: if k in nmap_esteet: k = emap_este line = line+k emap.append(line) return emap def muutapiste(p,merkki,maplist): # Palauttaa uuden maplistin jossa on pisteen kohdalle sijoitettu uusi merkki line = maplist[p[1]-1] # Kaivetaan kartasta oikea rivi maplist[p[1]-1] = line[0:p[0]-1]+merkki+line[p[0]:] # Muutetaan riviä niin, että korvataan koordinaattia vastaava kirjain halutuksi return maplist def luemap(tiedosto): f = open(tiedosto,'r') textmap = [] for line in f.readlines(): if line[-1] == '\n': textmap.append(line[0:-1]) else: textmap.append(line) return textmap maplist = nmap2emap(vmap2map(luemap(map_tiedosto))) # Luetaan kartta maplist listaan niin että siinä ei ole välejä if map_aloitus not in ''.join(maplist): print 'Kartassa ei ole aloituspistettä!' sys.exit() if map_lopetus not in ''.join(maplist): print 'Kartassa ei ole lopetuspistettä!' sys.exit() # Tulostetaan ratkaisematon kartta print '\nRATKAISEMATON' for f in reunusta(map2vmap(maplist)): print f.replace(nmap_vapaat[0],' ') reitti = lyhyin(maplist,map_aloitus,map_lopetus,nmap_vapaat,nmap_esteet,1) if reitti == -1: print 'Reittiä ei ole mahdollista muodostaa' sys.exit() if len(reitti) > 1: for piste in reitti: # Käydään reitin pisteet läpi maplist = muutapiste(piste,'+',maplist) # Käytetään muutapiste funktiota muuttamaan kartassa reitin pisteet +:ksi # Tulostetaan ratkaistu kartta print '\nRATKAISTU' for f in reunusta(map2vmap(maplist)): print f.replace(nmap_vapaat[0],' ')
Aihe on jo aika vanha, joten et voi enää vastata siihen.