食人者与传教士问题python-人工智能算法

Cannibals and missionaries problem python -artificial intelligence algorithm

我正在尝试解决 python 中的 cannibals and missionaries problem(有一些额外的标准,但主要思想是 classic )。

因此,在 class Graph 中,我初始化状态(食人者的数量、传教士的数量、船上的可用座位、食物单位(如果有,传教士可以喂食食人者)食人者多于传教士),等等

然后我的方法 genereazaSuccesori 无法正常工作,因为我做错了什么,我不知道是什么。所以这个方法应该为一个节点(参数nodCurent)生成后继者。

根据我在 Pycharm 中调试时看到的情况,主要问题是我的程序在执行第三个 for 之前以某种方式退出(我在 listaSuccesori 中追加,因此数组返回是空的。

有谁知道我的代码哪里做错了吗?特别是为什么我的代码不执行第三个 for?

即使 link 在 python 中实现了这个问题的完整示例也会对我有帮助(但是有食物的那个也有食物,因为这里的事情变得更加混乱,基本的很漂亮简单)。

谢谢!

solver.py:

import math


class NodParcurgere:
    def __init__(self, info, parinte):
        self.info = info
        self.parinte = parinte  # parintele din arborele de parcurgere

    def obtineDrum(self):
        l = [self];
        nod = self
        while nod.parinte is not None:
            l.insert(0, nod.parinte)
            nod = nod.parinte
        return l

    def afisDrum(self):  # returneaza si lungimea drumului
        l = self.obtineDrum()
        for nod in l:
            print(str(nod))
        return len(l)

    def contineInDrum(self, infoNodNou):
        nodDrum = self
        while nodDrum is not None:
            if (infoNodNou == nodDrum.info):
                return True
            nodDrum = nodDrum.parinte

        return False

    def __repr__(self):
        sir = ""
        sir += str(self.info) + "\n"
        return (sir)

    def __str__(self):
        sir = ""
        sir += str(self.info) + "\n"
        return (sir)


class Graph:  # graful problemei
    def __init__(self, numeFisier):
        f = open(numeFisier, "r")
        textFisier = f.read()
        infoFisier = textFisier.split("\n")
        for i in infoFisier:
            date_citite = i.split("=");
            print(date_citite);
            if date_citite[0] == "N1":
                Graph.N1 = int(date_citite[1]);  # N1 canibali,
            if date_citite[0] == "N2":
                Graph.N2 = int(date_citite[1]);  # N2 misionari
            if date_citite[0] == "Nr":
                Graph.Nr = int(date_citite[
                    1]);  # La fiecare Nr deplasari cu barca (de la un mal la celalalt) un loc din barca se va degrada
            if date_citite[0] == "MalInitial":
                Graph.MalInitial = date_citite[1];
            if date_citite[0] == "MalFinal":
                Graph.MalFinal = date_citite[1];
            if date_citite[0] == "M":
                Graph.M = int(date_citite[1]);
        f.close();
        canibali_mal_opus = 0
        misionari_mal_opus = 0
        pozitie_barca_mal_opus = 0
        pozitie_barca_mal_initial = 1
        nr_unitati_hrana_opus = 0
        nr_unitati_hrana_initial = 0
        numar_deplasari = 0;
        f = open(numeFisier, "r")
        textFisier = f.read()
        infoFisier = textFisier.split("\n")
        for i in infoFisier:
            date_citite = i.split("=");
            #print(date_citite);
            if date_citite[0] == "K":
                nr_unitati_hrana_initial = int(date_citite[1])
        self.start = (
            Graph.N1, Graph.N2, canibali_mal_opus, misionari_mal_opus, pozitie_barca_mal_initial,
            nr_unitati_hrana_initial,
            nr_unitati_hrana_opus, numar_deplasari);

        # TODO care e starea finala buna?
        self.scopuri = [(0, 0, 0, 0, 0, 0, 0, 0)]
        #print("stare initiala", self.start);

        # nr canibali pe mal initial si pe mal opus
        # nr misionari mal initial si mai opus

    def genereazaSuccesori(self, nodCurent):

        def test_conditie(mis, can):
            return mis == 0 or mis >= can

        listaSuccesori = []
        barca = nodCurent.info[4]
        if barca == 1:
            canMalCurent = nodCurent.info[0]
            misMalCurent = nodCurent.info[1]
            canMalOpus = int(Graph.N1) - int(canMalCurent)
            misMalOpus = int(Graph.N2) - int(misMalCurent)
            hranaMalCurent = nodCurent.info[5]
            hranaMalOpus = nodCurent.info[6]
        else:
            canMalOpus = nodCurent.info[0]
            misMalOpus = nodCurent.info[1]
            canMalCurent = Graph.N1 - canMalOpus
            misMalCurent = Graph.N2 - misMalOpus
            hranaMalCurent = nodCurent.info[6]
            hranaMalOpus = nodCurent.info[5]
        maxMisionariBarca = min(int(Graph.M - nodCurent.info[7] % 3), misMalCurent)
        for misBarca in range(0,maxMisionariBarca + 1):
            if misBarca == 0:
                maxCanibaliBarca = min(Graph.M - nodCurent.info[7] % Graph.Nr, canMalCurent)
                minCanibaliBarca = 1  # pt ca barca nu merge singura
            else:
                maxCanibaliBarca = min(Graph.M - nodCurent.info[7] % 3 - misBarca, canMalCurent,
                                       misBarca + nodCurent.info[5] * 2)
                minCanibaliBarca = 0

            for canBarca in range(minCanibaliBarca, maxCanibaliBarca + 1):
                minHrana = math.ceil(nodCurent.info[0] - nodCurent.info[1] / 2)
                maxHrana = min(nodCurent.info[5], Graph.M - misBarca - canBarca)
                for hrana in range(minHrana, maxHrana):
                    hranaBarca = hrana;
                    canMalCurentNou = canMalCurent - canBarca
                    misMalCurentNou = misMalCurent - misBarca
                    canMalOpusNou = canMalOpus + canBarca
                    misMalOpusNou = misMalOpus + misBarca
                    nodCurent_list = list(nodCurent.info);
                    nodCurent_list[7] = nodCurent_list[7]+1;
                    nodCurent.info = tuple(nodCurent_list)
                    hranaNou = hranaMalCurent - hranaBarca;
                    hranaOpus=0;
                    if(canBarca > misBarca):
                        hranaOpus = hranaOpus + hranaBarca - canBarca/2;
                    else:
                        hranaOpus = hranaOpus + hranaBarca;

                    if not test_conditie(misMalCurentNou, canMalCurentNou):
                        continue
                    if not test_conditie(misMalOpusNou, canMalOpusNou):
                        continue
                    if barca == 1:  # testul este pentru barca nodului curent (parinte) deci inainte de mutare
                        infoNodNou = (canMalCurentNou, misMalCurentNou, 0)
                    else:
                        infoNodNou = (canMalOpusNou, misMalOpusNou, 1)
                    if not nodCurent.contineInDrum(infoNodNou):
                        listaSuccesori.append(NodParcurgere(infoNodNou, nodCurent))
        print("lista succesori",listaSuccesori)
        return listaSuccesori

    def testeaza_scop(self, nodCurent):
        return nodCurent.info in self.scopuri;

    def __repr__(self):
        sir = ""
        for (k, v) in self.__dict__.items():
            sir += "{} = {}\n".format(k, v)
        return (sir)


def breadth_first(gr):
    global nrSolutiiCautate
    # in coada vom avea doar noduri de tip NodParcurgere (nodurile din arborele de parcurgere)
    c = [NodParcurgere(gr.start, None)]
    continua = True  # variabila pe care o setez la false cand consider ca s-au afisat suficiente solutii
    while (len(c) > 0 and continua):
        # print("Coada actuala: " + str(c))
        # input()
        nodCurent = c.pop(0)

        if gr.testeaza_scop(nodCurent):
            print("Solutie:")
            nodCurent.afisDrum()
            input()
            nrSolutiiCautate -= 1
            if nrSolutiiCautate == 0:
                continua = False
        lSuccesori = gr.genereazaSuccesori(nodCurent)
        c.extend(lSuccesori)


def depth_first(gr):
    # vom simula o stiva prin relatia de parinte a nodului curent
    df(NodParcurgere(gr.noduri.index(gr.start), gr.start, None))


def df(nodCurent):
    global nrSolutiiCautate, continua
    if not continua:
        return
    print("Stiva actuala: " + "->".join(nodCurent.obtineDrum()))
    input()
    if gr.testeaza_scop(nodCurent):
        print("Solutie: ", end="")
        nodCurent.afisDrum()
        nrSolutiiCautate -= 1
        if nrSolutiiCautate == 0:
            continua = False
    lSuccesori = gr.genereazaSuccesori(nodCurent)
    for sc in lSuccesori:
        df(sc)


#############################################


def dfi(nodCurent, adancime):
    global nrSolutiiCautate, continua
    if not continua:
        return
    print("Stiva actuala: " + "->".join(nodCurent.obtineDrum()))
    input()
    if adancime == 1 and gr.testeaza_scop(nodCurent):
        print("Solutie: ", end="")
        nodCurent.afisDrum()
        nrSolutiiCautate -= 1
        if nrSolutiiCautate == 0:
            continua = False
            return
    if adancime > 1:
        lSuccesori = gr.genereazaSuccesori(nodCurent)
        for sc in lSuccesori:
            dfi(sc, adancime - 1)


def depth_first_iterativ(gr):
    for i in range(1, gr.nrNoduri + 1):
        if nrSolutiiCautate == 0:
            break
        print("-----------\nAdancime maxima: ", i)
        dfi(NodParcurgere(gr.noduri.index(gr.start), gr.start, None), i)


gr = Graph("input.txt")
nrSolutiiCautate = 4
breadth_first(gr)
nrSolutiiCautate = 4
continua = True
# depth_first(gr)
nrSolutiiCautate = 4
continua = True
# depth_first_iterativ(gr)

input.txt:

N1=4
N2=4
K=2
M=2
Nr=3
MalInitial=vest
MalFinal=est

实际输出:

['N1', '4']
['N2', '4']
['K', '2']
['M', '2']
['Nr', '3']
['MalInitial', 'vest']
['MalFinal', 'est']
['']
lista succesori []

为了找出究竟是什么阻止了您看似描述的 for 循环的进入,我在第 126 行提供的脚本中插入了一个简单的 print 语句:

第 124 到 127 行现在改为 (保持原始缩进)

                minHrana = math.ceil(nodCurent.info[0] - nodCurent.info[1] / 2)
                maxHrana = min(nodCurent.info[5], Graph.M - misBarca - canBarca)
                print(f"minHrana: {minHrana}, maxHrana: {maxHrana}")
                for hrana in range(minHrana, maxHrana):

我的输出是:

['N1', '4']
['N2', '4']
['K', '2']
['M', '2']
['Nr', '3']
['MalInitial', 'vest']
['MalFinal', 'est']
['']
minHrana: 2, maxHrana: 1
minHrana: 2, maxHrana: 0
minHrana: 2, maxHrana: 1
minHrana: 2, maxHrana: 0
minHrana: 2, maxHrana: 0
lista succesori []

要使range(start, stop)非空,必须满足条件start < stop

然而,无论是由于输入还是其他原因,我们观察到 范围 是空的。因此,您的 for 循环恰好执行了 0(换言之:零)次。