【Python】基于回溯法的水排序谜题

闲着没事用回溯法写了个解水排序谜题的Python代码,这里分享给大家,代码比较粗糙。

在数据定义部分,矩阵每一行是一个水瓶,从左到右表示从瓶底到瓶口的颜色。

输出结果(a -> b)表示按顺序从a瓶倒入b瓶。

import copy
from collections import Counter


class WaterSort(object):
    def __init__(self, shuiguan):
        self.shuiguan_origin = shuiguan  # 原始水管
        self.shuiguan_current = copy.deepcopy(self.shuiguan_origin)  # 当前水管
        self.visited = []  # 试过的失败操作
        self.orderList = []  # 当前操作
        self.orderflag = 0  # 是否存在有效操作

    def check_color(self, x):
        # 检查x中是否颜色相同
        d = dict(Counter(x))
        if len(d) <= 1:
            return 1
        else:
            return 0

    def check_complete(self):
        # 检查是否排序完成
        for shuiguan in self.shuiguan_current:
            if len(shuiguan) == 0:
                continue
            elif len(shuiguan) < 4:
                return 0
            else:
                if self.check_color(shuiguan) == 0:
                    return 0
        return 1

    def order(self, o):
        # 执行操作o:(a,b),由a倒入b
        while 1:
            if len(self.shuiguan_current[o[0]]) == 0:
                break
            if len(self.shuiguan_current[o[1]]) == 0:
                self.shuiguan_current[o[1]].append(self.shuiguan_current[o[0]][-1])
                del self.shuiguan_current[o[0]][-1]
            elif len(self.shuiguan_current[o[1]]) < 4 and self.shuiguan_current[o[0]][-1] == \
                    self.shuiguan_current[o[1]][-1]:
                self.shuiguan_current[o[1]].append(self.shuiguan_current[o[0]][-1])
                del self.shuiguan_current[o[0]][-1]
            else:
                break

    def sort(self):
        shuiguan_visited = []
        shuiguan_visited.append(copy.deepcopy(self.shuiguan_current))
        print(self.shuiguan_current)
        while self.check_complete() == 0:
            self.orderflag = 0
            for i in range(len(self.shuiguan_current)):
                # i被倒水管
                if len(self.shuiguan_current[i]) == 4:
                    # 被倒水管满
                    continue
                for j in range(len(self.shuiguan_current)):
                    # j倒出水管
                    # 即j倒i
                    if j == i or len(self.shuiguan_current[j]) == 0:
                        # 同一水管或倒出水管空
                        continue
                    if len(self.shuiguan_current[i]) == 0 and self.check_color(self.shuiguan_current[j]):
                        # 被倒水管空且倒出水管颜色相同
                        continue
                    remainLen = 4 - len(self.shuiguan_current[i])  # 水管剩余长度
                    if len(self.shuiguan_current[j]) > remainLen and self.check_color(
                            self.shuiguan_current[j][(-remainLen - 1):]):
                        # 如果j倒入i后仍剩余倒出颜色
                        continue
                    self.orderList.append((j, i))  # 执行倒水操作
                    if self.orderList in self.visited:
                        self.orderflag = 0
                        self.orderList = self.orderList[:-1]  # 回退一步
                        continue
                    if len(self.shuiguan_current[i]) == 0:
                        self.order((j, i))  # 倒水
                        print(self.shuiguan_current)
                        if self.shuiguan_current in shuiguan_visited:
                            self.orderflag = 0
                            # 如果返回之前的状态,则操作无效
                            self.visited.append(copy.deepcopy(self.orderList))  # 记录无效操作
                            self.orderList = self.orderList[:-1]  # 回退一步
                            # 水管状态回退
                            self.shuiguan_current = copy.deepcopy(self.shuiguan_origin)
                            for o in self.orderList:
                                self.order(o)
                            print(self.shuiguan_current)
                            # continue
                        else:
                            self.orderflag = 1
                            shuiguan_visited.append(copy.deepcopy(self.shuiguan_current))
                            # break
                    elif len(self.shuiguan_current[i]) < 4 and self.shuiguan_current[i][-1] == self.shuiguan_current[j][
                        -1]:
                        self.order((j, i))  # 倒水
                        print(self.shuiguan_current)
                        if self.shuiguan_current in shuiguan_visited:
                            self.orderflag = 0
                            # 如果返回之前的状态,则操作无效
                            self.visited.append(copy.deepcopy(self.orderList))  # 记录无效操作
                            self.orderList = self.orderList[:-1]  # 回退一步
                            # 水管状态回退
                            self.shuiguan_current = copy.deepcopy(self.shuiguan_origin)
                            for o in self.orderList:
                                self.order(o)
                            print(self.shuiguan_current)
                            # continue
                        else:
                            self.orderflag = 1
                            shuiguan_visited.append(copy.deepcopy(self.shuiguan_current))
                            # break
                    else:
                        # i不空是管且颜色不可倒
                        self.orderflag = 0
                        self.visited.append(copy.deepcopy(self.orderList))  # 记录无效操作
                        self.orderList = self.orderList[:-1]  # 回退一步
                if self.orderflag == 1:
                    break
            if self.orderflag == 0:
                # 目前操作死掉
                self.visited.append(copy.deepcopy(self.orderList))
                temp = copy.deepcopy(self.visited)
                self.visited = []
                for vis in temp:
                    if len(vis) > len(self.orderList) and vis[:len(self.orderList)] == self.orderList:
                        pass
                    else:
                        self.visited.append(vis)
                self.orderList = self.orderList[:-1]  # 回退一步
                self.shuiguan_current = copy.deepcopy(self.shuiguan_origin)
                for o in self.orderList:
                    self.order(o)
                print(self.shuiguan_current)
            else:
                self.orderflag = 0

        for o in enumerate(self.orderList):
            # print(o)
            print(o[0], ': (', o[1][0] + 1, '->', o[1][1] + 1, ')')


if __name__ == '__main__':
    shuiguan = [[],
                [],
                ['m', 'r', 'r', 't'],
                ['p', 'g', 'h', 'p'],
                ['h', 'y', 'y', 'g'],
                ['m', 'o', 'o', 'g'],
                ['m', 'y', 'p', 'h'],
                ['t', 'p', 'b', 'o'],
                ['b', 't', 'h', 'r'],
                ['b', 'y', 'o', 'b'],
                ['t', 'm', 'r', 'g']]
    d = {}
    for i in shuiguan:
        for j in i:
            try:
                d[j] += 1
            except:
                d[j] = 1
    for key in d:
        if d[key] != 4:
            print('颜色矩阵有误,请检查!!!')
    ws = WaterSort(shuiguan)
    ws.sort()

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@苏丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值