'Cannibals and missionaries problem python -artificial intelligence algorithm
I'm trying to solve the cannibals and missionaries problem in python (with some additional criteria, but the main idea is the classic one).
So, in the class Graph
, I initialize the state (number of cannibals, number of missionaries, available seats in the boat, units of food (missionaries can feed cannibals if there are more cannibals than missionaries), etc.
Then I have the method genereazaSuccesori
which is not working how is supposed to because I'm doing something wrong, I don't know what. So this method should generate successors for a node (parameter nodCurent
).
From what I saw while I was debugging in Pycharm, the main issue is that my program somehow exits before it executes the third for (where I append in listaSuccesori
, so the array returned is empty.
Does anyone know what I did wrong with my code? Especially why my code doesn't execute the third for?
Even a link with a full example of this problem implemented in python would help me (but the one where there is food as well because things get messier here, the basic one is pretty easy).
Thanks!
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
Actual output:
['N1', '4']
['N2', '4']
['K', '2']
['M', '2']
['Nr', '3']
['MalInitial', 'vest']
['MalFinal', 'est']
['']
lista succesori []
Solution 1:[1]
As to find out what exactly prevents the for
loop you seemingly describe to be entered, I inserted a simple print
statement into the script you gave in line 126:
lines 124 to 127 now read (keeping original indentation):
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):
My output is:
['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 []
For a range(start, stop)
to be non-empty, it must satisfy the condition start < stop
.
What we observe, however, whether because of the input or for other reasons, is that the range is empty. Consequently, your for
loop is executed exactly 0 (in words: zero) times.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |