My state machine in Python runs into infinite loop - python

I am new to python. My code runs into infinite loop, keeps adding & printing numberCycles. My logic in C++ works fine.
Would you please help to identify why?
The first line of input is the number of simulations.
The next line is the number of minutes for a single reproductive cycle.
The next line is the number of rows (x), followed by a single space, and followed by number of columns (y).
The next group of y lines will have x number of characters, with a single period (.) representing a blank space and a single capitol B representing a starting Bunny tries to reproduce to up, right, down, left direction. If there is a existing bunny, then it goes to sleep.
Input.txt
2 # 2 simulations
5 # 5 minutes/cycle
3 3 # 3*3 map
...
.B.
...
1
4 4
B.BB
..B.
...
B.B
Spot.py
#!/usr/bin/env python
class Spot(object):
isBunny = bool()
nextCycle = 0
UP = 0
RIGHT = 1
DOWN = 2
LEFT = 3
SLEEP = 4
def __init__(self, newIsBunny):
self.isBunny = newIsBunny
self.nextCycle = self.UP
def setNextCycle(self):
if (self.nextCycle != self.SLEEP):
self.nextCycle += 1
def getNextCycle(self):
return self.nextCycle
def getIsBunny(self):
return self.isBunny
def makeBunny(self):
if not self.isBunny:
self.nextCycle = self.UP
self.isBunny = True
Bunny.py
#!/usr/bin/env python
from Spot import Spot
import os
class Bunny(object):
#classmethod
def main(cls, args):
with open(os.path.expanduser('~/Desktop/input.txt')) as f:
numSims = int(f.readline())
myMap = []
print numSims
minPerCycle= int(f.readline())
print minPerCycle
for k in xrange(numSims):
xyLine= f.readline()
row = int(xyLine.split()[0])
col = int(xyLine.split()[1])
print row,col
for i in range(0,row):
myLine = f.readline()
myMap.append([])
for j in range(0,col):
myMap[i].append(Spot(myLine[j] == 'B'))
numCycles = 1
if cls.isFilled(row,col,myMap):
numCycles = 0
while not cls.isFilled(row,col,myMap):
numCycles += 1
print numCycles
for m in range(0,row):
for n in range(0,col):
if myMap[m][n].getIsBunny():
if myMap[m][n].getNextCycle() == Spot.UP:
if m>0:
myMap[m-1][n].makeBunny()
break
elif myMap[m][n].getNextCycle() == Spot.RIGHT:
if n<col-1:
myMap[m][n+1].makeBunny()
break
elif myMap[m][n].getNextCycle() == Spot.DOWN:
if m<row-1:
myMap[m+ 1][n].makeBunny()
break
elif myMap[m][n].getNextCycle() == Spot.SLEEP:
if n>0:
myMap[m][n- 1].makeBunny()
break
myMap[m][n].setNextCycle()
time = numCycles * minPerCycle
print "It took " , time , " minutes for the bunnies to take over the world!\n"
del myMap[:]
f.close()
#classmethod
def isFilled(cls,row,col,myMap):
for a in range(0,row):
for b in range(0,col):
if not myMap[a][b].getIsBunny():
return False
return True
if __name__ == '__main__':
import sys
Bunny.main(sys.argv)

It never goes to the left. Also, you set a break for the inner loop, so, myMap[m][n].setNextCycle() is never called. I just saw your C++ code and you translated it to Python with errors (using Spot.SLEEP instead of Spot.LEFT).
The break statement makes sense in C++ because you want to break the switch. Here, you are using if..else.
It should be something like:
while not cls.isFilled(row, col, myMap):
numCycles += 1
print numCycles
for m in range(0,row):
for n in range(0,col):
if myMap[m][n].getIsBunny():
if myMap[m][n].getNextCycle() == Spot.UP:
if m>0:
myMap[m-1][n].makeBunny()
elif myMap[m][n].getNextCycle() == Spot.RIGHT:
if n<col-1:
myMap[m][n+1].makeBunny()
elif myMap[m][n].getNextCycle() == Spot.DOWN:
if m<row-1:
myMap[m+ 1][n].makeBunny()
elif myMap[m][n].getNextCycle() == Spot.LEFT:
if n>0:
myMap[m][n-1].makeBunny()
myMap[m][n].setNextCycle()

Related

Annotating adjacent values in a list

It's supposed to be a roll of dice (random) then adjacent values (runs) are supposed to be in ( ). One challenge is using the current - 1 with the 0 index (think I got that resolved by using range(len(dieRun) -1). But another challenge is using 'current + 1' as it tends to 'out of range' errors.
One thought I have is to maybe build a function to compare the values for adjacents? Then use whatever return I get from that to reference a variable, then use that variable in a formatted Print of the dieRun? But, I don't see how that would be better as then I'd still have to figure out how to place that variable as a "(" or ")" with the print(dieRun) list.
Still a newb.
def main():
from random import randint
counter = 0
inRun = 0
dieRun = []
while counter < 20:
roll = randint(0,6)
dieRun.append(roll)
counter = counter +1
index = 0
counter = 0
value = 0
inRun == False
print(dieRun) # just to see what I'm working with
while counter < len(dieRun):
for i in range(0, len(dieRun)-1):
if dieRun[i] != dieRun[i-1]:
print(")" , end= "")
inRun = False
counter = counter + 1
if dieRun[i] == dieRun[i+1]:
inRun = True
print("(")
counter = counter + 1
print(dieRun[i])
if inRun:
print("(")
if inRun :
print(")", end="")
main()
if you want the output like: 1(3 3) 4 5 (6 6 6) 2 1 3 (2 2) 1 (4 4) 5 6 1 2
from random import randint
dieRun = []
for i in range(20):
roll = randint(0,6)
dieRun.append(roll)
inRun = False
print(dieRun)
for i, n in enumerate(dieRun):
if i < len(dieRun)-1:
if not inRun:
if n == dieRun[i+1]:
print('(', n,' ', end='')
inRun = True
else:
print(n,' ', end='')
else:
if n != dieRun[i+1]:
print(n, ')',' ', end='')
inRun = False
else:
print(n,' ', end='')
else:
if dieRun[i-1] == n:
print(n, ')')
else:
print(n)
just a thought, hope it help.
Just a quick fix, I have commented in the code.
For the inline print, you have provided the solution 'print(")" , end= "")', but I don't know why you didn't make it for every print().
if dieRun[i] != dieRun[i-1]: # will check the first number with last number
dieRun[0] != dieRun[-1]: # [-1] is the last item in the list
if dieRun[i] == dieRun[i+1]: # will index out of length
dieRun[len(..)-1] != dieRun[len(..)]: # [len(..)] wil be out of range
Since the head and tail of the list will always cause problem, I just chopped them off from the for loop, and do it manually.
There must be some cleaner solution:
from random import randint
counter = 0
inRun = 0
dieRun = []
while counter < 20:
roll = randint(0,6)
dieRun.append(roll)
counter = counter +1
index = 0
counter = 0
value = 0
inRun == False
print(dieRun)
# while counter < len(dieRun): # while loop is redundant with the for loop
print('(', dieRun[0],' ', end='') # print the first number manually
for i in range(1, len(dieRun)-1):
if dieRun[i] != dieRun[i-1]:
print(")(" , end= "") # change ")" to ")("
inRun = False
counter = counter + 1
"""
these are redundant, just like if True, don't need elif not True
# if dieRun[i] == dieRun[i+1]:
# inRun == True
# print("(", end='')
# counter = counter + 1
"""
print(dieRun[i],' ', end='')
print(dieRun[-1],')', end='') # print the last number manually

Python printing before/after different lines

I have created some code long ago which helps to create a table in BBcode used in forums.
counter = 0
counter2 = 0
while True:
UserInput = input("")
if counter2 == 0:
print ("[tr]")
print ("[td][center]Label\n" + "[img]" + str(UserInput) + "[/img][/center][/td]")
counter += 1
counter2 += 1
if counter % 5 == 0:
print ("[/tr]")
So if i input Image1.jpg ~ Image7.jpg on seperate lines, the output is as shown below
> [tr]
> [td][center]Label[img]Image1.jpg[/img][/center][/td]
> [td][center]Label[img]Image2.jpg[/img][/center][/td]
> [td][center]Label[img]Image3.jpg[/img][/center][/td]
> [td][center]Label[img]Image4.jpg[/img][/center][/td]
> [td][center]Label[img]Image5.jpg[/img][/center][/td]
> [/tr]
> [td][center]Label[img]Image6.jpg[/img][/center][/td]
> [td][center]Label[img]Image7.jpg[/img][/center][/td]
Currently, the code only inserts [/tr] at the end of ever 5 images.How does one make it so that [/tr] is also printed at the end of output no matter how many jpgs are entered?
How can I print [tr] at the start and join it with the line below, and then not print again until a [/tr] has been printed?
Apologies for my crap English & explanation skills.
(Current progress)
counter = 0
while True:
UserInput = input("")
if counter == 0 or counter % 5 == 0:
print("[tr]", end = "")
print ("[td][center]Label\n" + "[img]" + str(UserInput) + "[/img][/center][/td]")
counter += 1
if counter % 5 == 0:
print("[/tr]")
After reading what you wrote 5 times I believe what you want is:
print("[tr]")
while True:
counter = 0
UserInput = input("")
if UserInput == "exit":
exit(0)
print("[tr]", end = "")
while (counter !=5):
print ("[td][center]Label\n" + "[img]" + str(UserInput) + "[/img][/center][/td]")
counter += 1
print ("[/tr]")
print("[/tr]")
So what happens here is you print [tr] in the same line as the first print from the inside while as you wanted. the [/tr] is in a new line but you can put it in the same by adding end = "" to the second print as well.
Separate the functions. Get the list of images, then process it:
def bbcode(images):
for i in range(0,len(images),5):
print('[tr]')
for image in images[i:i+5]:
print(f'[td][center]Label[img]{image}[/img][/center][/td]')
print('[/tr]')
def get_images():
images = []
while True:
image = input('Image? ')
if not image: break
images.append(image)
return images
images = get_images()
bbcode(images)
You can do it as one long script, but it isn't as clear:
count = 0
while True:
image = input('Image? ')
if not image:
break
count = (count + 1) % 5
if count == 1:
print('[tr]')
print(f'[td][center]Label[img]{image}[/img][/center][/td]')
if count == 0:
print('[/tr]')
if count != 0:
print('[/tr]')
Below is the result with some commentary. To update for your specifications, just set the max_item_blocks variable to whatever you want.
### your main body element with {} to pass a number
element = '[td][center]Label[img]Image{}.jpg[/img][/center][/td]'
### The number of "blocks" you want to print.
max_item_blocks = 3
### Define a start value of 1
start = 1
### Our simple loop with join() function
while max_item_blocks > 0:
### End value is start + 5
end = start + 5
print('[tr]\n' + '\n'.join([element.format(i) for i in range(start, end)]) + '\n[\\tr]')
### Start takes ending value
start = end
### Ending value is now start + 5
end = start + 5
### Reduce our block counts by 1
max_item_blocks -= 1
Output for 3 blocks:
[tr]
[td][center]Label[img]Image1.jpg[/img][/center][/td]
[td][center]Label[img]Image2.jpg[/img][/center][/td]
[td][center]Label[img]Image3.jpg[/img][/center][/td]
[td][center]Label[img]Image4.jpg[/img][/center][/td]
[td][center]Label[img]Image5.jpg[/img][/center][/td]
[\tr]
[tr]
[td][center]Label[img]Image6.jpg[/img][/center][/td]
[td][center]Label[img]Image7.jpg[/img][/center][/td]
[td][center]Label[img]Image8.jpg[/img][/center][/td]
[td][center]Label[img]Image9.jpg[/img][/center][/td]
[td][center]Label[img]Image10.jpg[/img][/center][/td]
[\tr]
[tr]
[td][center]Label[img]Image11.jpg[/img][/center][/td]
[td][center]Label[img]Image12.jpg[/img][/center][/td]
[td][center]Label[img]Image13.jpg[/img][/center][/td]
[td][center]Label[img]Image14.jpg[/img][/center][/td]
[td][center]Label[img]Image15.jpg[/img][/center][/td]
[\tr]

alien invasion of python code in the terminal - (why is it appending the letter D to the output?)

So I'm working on a dorky little algorithm-- the point of which is very dull. All I want to know is why I'm the letter "D" is attached to the output on the terminal.
When the answer is 1, it gives me back 1D. When the answer is 2, it spits out 2D, etc. Why?
I don't think it has much to do with the code. The code is below if you think so. It might have to do with the way I'm ending the input stream, which is by pressing Ctrl + D (mac). It's not giving me 1^D, it's giving me 1D. Why?
if __name__ == '__main__':
input = sys.stdin.read()
n, *data = map(int, input.split())
segments = list(map(lambda x: Segment(x[0], x[1]), zip(data[::2], data[1::2])))
points = optimal_points(segments)
print(int(len(points)))
for p in points:
print(p, end=' ')
It basically says, blah blah blah, get a list of numbers from the input stream / terminal, like this:
3
1 3
2 5
3 6
and do this to it:
def is_between(num_to_check, start, end):
return num_to_check >= start and num_to_check <= end
def optimal_points(segments):
end_first_segements = sorted(segments, key=attrgetter('end'))
count = 1
i = 1
current_end = end_first_segements[i -1 ].end
next_seg = end_first_segements[i]
end_points=[current_end]
while i <len(end_first_segements):
s = next_seg.start
e = next_seg.end
if(is_between(current_end, s, e)):
try:
i += 1
next_seg = end_first_segements[i]
except IndexError:
break;
else:
try:
count +=1
end_points.append(next_seg.end)
next_seg = end_first_segements[i+1]
current_end = next_seg.end
except IndexError:
break;
return end_points
See, there's nothing in the code that says, "hey, you should attach the letter D to the output for no reason".
I keep seeing this in other little programs I've done as well. So I think it has to do with the terminal verse any code that I write. Thoughts?
The entire .py file:
# Uses python3
import sys
from collections import namedtuple
from operator import attrgetter
Segment = namedtuple('Segment', 'start end')
def is_between(num_to_check, start, end):
return num_to_check >= start and num_to_check <= end
def optimal_points(segments):
end_first_segements = sorted(segments, key=attrgetter('end'))
count = 1
i = 1
current_end = end_first_segements[i -1 ].end
next_seg = end_first_segements[i]
end_points=[current_end]
while i <len(end_first_segements):
s = next_seg.start
e = next_seg.end
if(is_between(current_end, s, e)):
try:
i += 1
next_seg = end_first_segements[i]
except IndexError:
break;
else:
try:
count +=1
end_points.append(next_seg.end)
next_seg = end_first_segements[i+1]
current_end = next_seg.end
except IndexError:
break;
return end_points
if __name__ == '__main__':
input = sys.stdin.read()
n, *data = map(int, input.split())
segments = list(map(lambda x: Segment(x[0], x[1]), zip(data[::2], data[1::2])))
points = optimal_points(segments)
print(int(len(points)))
for p in points:
print(p, end=' ')
I cannot exactly reproduce your exact issue, but I do see something strange where the last line of output ends with a % sign in linux.
So my minimal working example to reproduce this behaviour is simply:
print('1 2', end=' ')
If I add an empty print statement at the end of the program this removes the behaviour, ie by adding print() at the very end.

My Python interpreter for Self-modifying Brainf*** has a bug

I wrote this Python interpreter for a language called Self-modifying Brainf*** (SMBF). Today I discovered a bug where if the program dynamically creates code at the initial cell or after on the tape, it will not be executed. I wrote this interpreter to look as close as possible to the Ruby interpreter on the linked page. Note that this bug may exist in the original Ruby interpreter, too. I don't know, I haven't used it.
The way SMBF is different from normal BF is that the source code is placed on the tape to the left of the cell that the pointer starts at. So the program <. would print the last character of the source (a period). This works.
Note that I trimmed some code out so it's still runnable but takes less space in this post.
The interpreter:
from __future__ import print_function
import os, sys
class Tape(bytearray):
def __init__(self):
self.data = bytearray(b'\0' * 1000)
self.center = len(self.data) // 2
def __len__(self):
return len(self.data)
def __getitem__(self, index):
try:
return self.data[index + self.center]
except:
return 0
def __setitem__(self, index, val):
i = index + self.center
if i < 0 or i >= len(self.data):
# resize the data array to be large enough
new_size = len(self.data)
while True:
new_size *= 2
test_index = index + (new_size // 2)
if test_index >= 0 and test_index < new_size:
# array is big enough now
break
# generate the new array
new_data = bytearray(b'\0' * new_size)
new_center = new_size // 2
# copy old data into new array
for j in range(0, len(self.data)):
new_data[j - self.center + new_center] = self.data[j]
self.data = new_data
self.center = new_center
self.data[index + self.center] = val & 0xff
class Interpreter():
def __init__(self, data):
self.tape = Tape()
# copy the data into the tape
for i in range(0, len(data)):
self.tape[i - len(data)] = data[i]
# program start point
self.entrypoint = -len(data)
def call(self):
pc = self.entrypoint
ptr = 0
# same as -len(self.tape) // 2 <= pc + self.tape.center < len(self.tape) // 2
while -len(self.tape) <= pc < 0: # used to be "while pc < 0:"
c = chr(self.tape[pc])
if c == '>':
ptr += 1
elif c == '<':
ptr -= 1
elif c == '+':
self.tape[ptr] += 1
elif c == '-':
self.tape[ptr] -= 1
elif c == '.':
print(chr(self.tape[ptr]), end="")
elif c == ',':
sys.stdin.read(1)
elif c == '[':
if self.tape[ptr] == 0:
# advance to end of loop
loop_level = 1
while loop_level > 0:
pc += 1
if chr(self.tape[pc]) == '[': loop_level += 1
elif chr(self.tape[pc]) == ']': loop_level -= 1
elif c == ']':
# rewind to the start of the loop
loop_level = 1
while loop_level > 0:
pc -= 1
if chr(self.tape[pc]) == '[': loop_level -= 1
elif chr(self.tape[pc]) == ']': loop_level += 1
pc -= 1
pc += 1
# DEBUG
#print(pc, self.tape.data.find(b'.'))
def main():
# Working "Hello, World!" program.
#data = bytearray(b'<[.<]>>>>>>>>+\x00!dlroW ,olleH')
# Should print a period, but doesn't.
data = bytearray(b'>++++++++++++++++++++++++++++++++++++++++++++++')
intr = Interpreter(data)
intr.call()
#print(intr.tape.data.decode('ascii').strip('\0'))
if __name__ == "__main__":
main()
The problem:
This line is how I set the program (so I can run this on Ideone.com):
data = bytearray(b'++++++++++++++++++++++++++++++++++++++++++++++')
The program adds to the cell until it is 46, which is the decimal value for an ASCII ., which should print the current cell (a period). But for some reason, the program counter pc never gets to that cell. I want the program to run all code it finds until it hits the end of the tape, but I'm having a hard time getting the program counter to take into account the center of the tape, and ensure that it's still correct if the tape is resized in __setitem__.
The relevant line is (what I was trying out):
while -len(self.tape) <= pc < 0:
which was originally this:
while pc < 0:
So I think that the while line either needs to be adjusted, or I need to change it to while True: and just use a try/except while getting chr(self.tape[pc]) to determine if I've hit the end of the tape.
Does anyone see what is wrong or how to fix it?
Found a solution thanks to Sp3000.
self.end = 0 in Tape.__init__, self.end = max(self.end, index+1) in Tape.__setitem__ and replace the while in Interpreter.call with while pc < self.tape.end:.

python: program hanging! (print issue maybe?)

So, I'm quite nooby at python. I decided to make a program that makes prime numbers. I know there's probably a function built in that does this but I decided to do it myself.
number = 1
numlist = list()
for x in range (0, 1000):
numlist.append("")
print "Created list entry " + str(x)
while True:
number = number + 1
if number % 2 != 0:
numscrollerA = 1
numscrollerB = 1
while numscrollerA <= number:
if float(number) / float(numscrollerA) == float(int(number)):
numlist[numscrollerA] = "true"
if float(number) / float(numscrollerA) != float(int(number)):
numlist[numscrollerA] = "false"
numscrollerA = numscrollerA + 1
while numscrollerB <= number:
if numscrollerB != 1 and numscroller != number and numlist[numscrollerB] == "true":
primestatus = "false"
else:
primestatus = "true"
if primestatus == "true":
print number
I get "Created list entry x" 1000 times as I should. Then the program just hangs.
while numscrollerB <= number:
if numscrollerB != 1 and numscroller != number and numlist[numscrollerB] == "true":
primestatus = "false"
else:
primestatus = "true"
You don't increase numscrollerB in this loop, so it runs infinitedly. Anyway, You should rather use 'for loop':
for numscrollerB in range(1, number+1):
pass # do something
Your code is very unpythonic. Typical of a newcomer experienced in a different style of coding.
Your list is uneccessary.
In python you could create the list like this
def check_even(val):
#this contains your logic
return val % 2 == 0
evenslist = [check_even(i) for i in xrange(1, 1001)]
print numlist

Categories

Resources