推箱子游戏 最短路径 python实现

来源:互联网 发布:java helloworld代码 编辑:程序博客网 时间:2024/06/11 20:27

题目描述:


最短路径为:

uurrDDDDuuuulldRurDDDrddLLrruLuuulldRurDDDrdL

u表示向上,d表示向下,l表示向左,r表示向右。

大写表示人推着箱子一起动,小写表示人自己走。


代码用BFS实现。状态要分推着箱子一起走和人单独走,这两种状态转移是不同的。

由于代码中注释较详细,这里不过多解释。


代码:

# -*- coding: utf-8 -*-# @Time    : 2017/8/10 上午9:42# @Author  : Qi MO# @File    : BFS.py# @Software: PyCharm Community Editionlevel_file_path = '../数据/level_file.txt'class GameShortest:    def __init__(self,line, col=10):        """        给一个图,长度为100的字符串表示。        0空地 1墙 2箱子起始位置 3箱子终点位置 4人的起始位置        :param line: 地图,用字符串表示。如代码最后的每一行表示每一关的地图。        :param col: 地图的长宽,由于设定为10*10,默认为10        """        self.line = line        # sta和en 表示开始的状态,结束的状态        # sta只有2,4,0 2表示箱子开始位置,4表示人的位置,0表示其他。        # en只有1,3,0 1表示墙,3表示箱子结束位置,0表示其他。        # 现在只需要把sta状态中的2位置移动到en的3的位置即满足条件        self.sta = ''        self.en = ''        self.col = col        # px, py表示4的位置        self.px,self.py = -1,-1        # paths记录最短路径(可能有多条)        self.paths = []        # len记录最短路径长度 如        self.len = -1        self.pre()        self.BFS()        print(self.paths)    def pre(self):        """        1.获得sta开始状态和en结束状态        2.获得人的起始位置px,py        代码最后的第一关的地图可视化为        1111111111        1111111111        1110001111        1110221111        1114201111        1111100111        1111300111        1113300111        1111111111        1111111111        :return:        """        mp = []        for pos in range(0, 100, 10):            mp.append(self.line[pos:pos + 10])        # print(self.line)        # for x in mp:        #     print(x)        for pos, enum in enumerate(self.line):            cx, cy = pos // 10, pos % 10            if enum == '4':                self.px, self.py = cx, cy        # 现在只需要把sta开始的状态中的2位置移动到en的3的位置即满足条件        staDic = {'0': '0', '1': '0', '2': '2', '3': '0', '4': '4'}        enDic = {'0': '0', '1': '1', '2': '0', '3': '3', '4': '0'}        for x in self.line:            self.sta += staDic[x]            self.en += enDic[x]        # print(self.sta)        # print(self.en)    def is_ok(self,sta):        """        sta状态中的2位置移动到en的3的位置。        :param sta:        :return:        """        for s,e in zip(sta,self.en):            if e == '3' and s != '2':                return False        return True    def BFS(self):        """        BFS获得最短路径保存到paths中        :return:        """        # 4个方向,小写代表只是人移动,大写表示人推着箱子一起移动        dirs = [[-1,0,'u','U'],[1,0,'d','D'],[0,1,'r','R'],[0,-1,'l','L']]        # 把开始的状态进入队列(list模拟),状态包括字符串表示的当前状态、当前的路径、当前人的位置        states = [[self.sta,'',self.px,self.py]]        # 访问数组(dict模拟),访问过的状态(字符串)不再访问        visi = {}        visi[self.sta] = 1        s_len = 1000        while len(states)>0:            sta, path, px, py = states[0]            # 4状态的位置            ppos = px*self.col + py            states = states[1:]            if len(path)>s_len:                break            # 保存最短路径到paths中            if self.is_ok(sta):                if self.len == -1 or len(path) == self.len:                    self.paths.append(path)                    self.len = len(path)                continue            for dir in dirs:                cx, cy = px + dir[0], py + dir[1]                # 4挨着的状态的位置                pos = cx*self.col+cy                nx, ny = px + 2*dir[0], py + 2*dir[1]                # 4挨着挨着的状态的位置                npos = nx*self.col+ny                if not (nx>=0 and nx<self.col and ny>=0 and ny<self.col):                    continue                # python中字符串不可更改,于是把字符串变成list更改状态后再转换为字符串                if sta[pos] == '2' and sta[npos] == '0' and self.en[npos] != '1':                # 人和箱子一起推动,sta中连着的状态为4 2 0,en中第三个不能为1。推完之后sta变为0 4 2                    digits = [int(x) for x in sta]                    digits[ppos],digits[pos],digits[npos] = 0,4,2                    new_sta = ''.join(str(x) for x in digits)                    if new_sta not in visi:                        visi[new_sta] = 1                        states.append([new_sta, path+dir[3], cx, cy])                elif sta[pos] == '0' and self.en[pos] !='1':                # 人动箱子不动,sta中连着的状态为4 0,en中第二个不能为1。                    digits = [int(x) for x in sta]                    digits[ppos], digits[pos]  = 0, 4                    new_sta = ''.join(str(x) for x in digits)                    if new_sta not in visi:                        visi[new_sta] = 1                        states.append([new_sta, path + dir[2], cx, cy])if __name__ == '__main__':    f = open(level_file_path, encoding='utf-8')    cnt = 0    while(1):        line = f.readline()        line = line.strip('\n')        if len(line)==0 :            break        gs = GameShortest(line)"""level_file.txt中内容:11111111111111111111111000111111102211111114201111111110011111113001111113300111111111111111111111111111111111104000000110000200111001101011100100101110010010111001011001110030000111111111111111111111111111111111111111111111111111111031111114002000111023002011111131111111111111111111111111111111111111111111111111111111111000111111102211111110133111111023011111100401111111111111111111111111111111111111111111111111111111111111111100000111112111001113030020111400100011111111111111111111111111111111111111111111111111111111111111111001111110000001111100122011114030031111111111111111111111111111111111111111111100400011100000001110011100111100110011110201301111000020111113111111111111111111111111111111111111111111111111111111111100111111100320001110131210111000000411111111111111111111111111111111111111111111111111111111111111110000011110011101111000202011100013341111111111111111111111111111111111111111111111111111111001111111100041111111010111113121001111320010111130002011111111111111111111111111111111111111111111000001111131103111110402011111001201111100100111111111111111111111111111111111111111111111111111111110000111111311201111023400111100100011110000111111111111111111111111111111111111111111111111111111111110011111102041111110200111113001011111300001111111111111111111111111111111111111111111111111111111143001111100000111110010211111001203111111101011111110001111111111111111111111111111111111111111111111111111110000111111020211111103342011111113001111111111111111111111111111111111111111111111111111111100011111002301111140323011111101201111110001111111111111111111111111111111111111111111111111111111110031111102010111110020011111031401111100001111111111111111111111111111111111111111111111111111111111110411111311001111033020111102120011110000111111111111111111111111111111111111111111111111111111110001111111003301111100112111111001001111120004111110011111111111111111111111111111111111111111111111100001111103032111110024001111111010111111100011111111111111111111111111111111每一关的最短路径:['uurrDDDDuuuulldRurDDDrddLLrruLuuulldRurDDDrdL']['drrRRurDDDDDrdLLL']['rrdrUrrrdLLulDullldR']['lluRRdrUllluuurrDDuulldRurD']['urrrrdrruulullllDurrrrdrddllullLrrrdrruLLL']['uurrrrDulllddrrRuulDrdL']['drrdddrdLLLuLDlUUUluRRRRurDDD']['uullLLddrrUdlllluuRurDrRddrruuLLL']['lUlLLdlluururrrrDDrdLullldlluRRRRllluurrrrdD']['ddrddLLulLdlUrrrdrruuluulldDuurrddrddllLLrruLL']['luurrrdrdLLLrrrddlUruuulllldDrddlUUrrRdrU']['ddlluluRuurrrDrddlluLrdrruLLddlluU']['dddlluluuRDrruulDrdLLulDrDLurrrddlLL']['drrdDrrddllUUUUruLdrDldR', 'drrdDrrddllUUUUrDldRuuuL']['drruLLLuulldRurDurDD']['urRdddrrUULLulldRururrD']['uLrddlluluuRDrrruullDldRRdrUU']['dddlUllllddrUUddrrUruLLrrruulDrdLL']['llldlUUUluurDrrrDDrdLLLulUluRRlddrddlUUUluR']['ulldRurDrrddllUUluurrDLLdrddrruuLrddlluU']"""