Python Brainf*** – Bugs on while loops - python

I am a relative beginner to python, and in order to strengthen my skills, I am (attempting) to write a compiler for the Brainfu** language. All is good, except for the bracket [] loops. The program I am using to test my code is >++[>++<-]>+, which should set cell 2 to 5. When I run this, however, it does this:
0 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 0 >
1 [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 1 +
2 [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2 +
3 [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2 [
4 [0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 0 >
5 [0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 1 +
6 [0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2 +
7 [0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2 <
8 [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 1 -
3 [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 1 [
10 [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2 >
11 [0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 3 +
[0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
(The lines are formatted in the iteration, then the list at that point, then the value it's focused on and then the character it's running.)
My current code is
def generateArray(code):
array = []
for i in range(0,20):
array.append(0);
return array
def run(code):
print code
data = generateArray(code)
chars = list(code)
pointer = 0
for i in range(0, len(chars)):
current = chars[i]
if(current == "+"):
data[pointer] += 1
if(current == ">"):
pointer += 1
if(current == "-"):
data[pointer] -= 1
if(current == "<"):
pointer -= 1
if(current == "."):
print str(chr(data[pointer]))
if(current == ","):
given = raw_input()
data[pointer] = ord( given )
if(current == "["):
posOfEnd = chars[i:len(chars)].index("]")
if(data[pointer] == 0):
i += posOfEnd+1
if(current == "]"):
posOfBegin = len(chars) - 1 - chars[::-1].index('[')
i = posOfBegin
print i, data, data[pointer], chars[i]
return data
print run(">++[>++<-]>+")
posOfEnd is trying to find out where the next bracket is, and posOfBegin is trying to find out where the previous bracket is.

I suppose the problem is your loop variable i which you modify during the loop:
i += posOfEnd+1
and
i = posOfBegin
However python for loops are different from their C/C++ counterparts. In python the variable i will be set to each element of the iterable you provide it, in this case range. range(n) evaluates to a list containing all numbers from 0 up to n-1. If you modify your loop variable during an iteration then this modification remains for only that iteration but for the next iteration the loop variable will be assigned the next element of the iterable (not preserving your modifications).
You might want to use a while loop instead.

Related

Why do we need to swap grid_model and next_grid_model?

This is a part of code of John Conway's GAME OF LIFE
import random
height = 100
width = 100
def randomize(grid, width, height):
for i in range(0, height):
for j in range(0, width):
grid[i][j] = random.randint(0,1)
grid_model = [0] * height
next_grid_model = [0] * height
for i in range(height):
grid_model[i] = [0] * width
next_grid_model[i] = [1] * width
def next_gen():
global grid_model, next_grid_model
for i in range(0, height):
for j in range(0, width):
cell = 0
count = count_neighbors(grid_model, i, j)
if grid_model[i][j] == 0:
if count == 3:
cell = 1
elif grid_model[i][j] == 1:
if count == 2 or count == 3:
cell = 1
next_grid_model[i][j] = cell
temp = grid_model
grid_model = next_grid_model
next_grid_model = temp
def count_neighbors(grid, row, col):
count = 0
if row-1 >= 0:
count = count + grid[row-1][col]
if (row-1 >= 0) and (col-1 >= 0):
count = count + grid[row-1][col-1]
if (row-1 >= 0) and (col+1 < width):
count = count + grid[row-1][col+1]
if col-1 >= 0:
count = count + grid[row][col-1]
if col + 1 < width:
count = count + grid[row][col+1]
if row + 1 < height:
count = count + grid[row+1][col]
if (row + 1 < height) and (col-1 >= 0):
count = count + grid[row+1][col-1]
if (row + 1 < height) and (col+1 < width):
count = count + grid[row+1][col+1]
return count
glider_pattern = [[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0]]
glider_gun_pattern = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
def load_pattern(pattern, x_offset=0, y_offset=0):
global grid_model
for i in range(0, height):
for j in range(0, width):
grid_model[i][j] = 0
j = y_offset
for row in pattern:
i = x_offset
for value in row:
grid_model[i][j] = value
i = i + 1
j = j + 1
if __name__ == '__main__':
next_gen()
temp = grid_model
grid_model = next_grid_model
next_grid_model = temp
What I want to ask is why we need to swap grid_model and next_grid_model?
Consider this small example
000
111
It should be followed by this grid
010
010
upper corners are 0, and surrounded by two 1, so they remain 0
lower corners are 1, and surrounded by one 1, so they become 0
upper middle pixel is 0 and surrounded by three 1, so it becomes 1.
lower middle pixel is 1 and surrounded by two 1, so it stays 1
Now, what would happen if you were using only one grid, that is compute this in situ:
You would start with grid
000
111
First pixel is 0, surround by two 1, so it stays 0, and grid stays
000
111
Second pixel is 0 surrounded by three 1, so it becomes 1. And grid becomes
010
111
Third pixel is 0, surrounded by three 1, so it becomes 1, and grid becomes
011
111
Fourth pixel (on 2nd line) is 1, surrounded by two 1, it stays 1.
011
111
Fifth pixel is 1, surrounded by four 1, it becomes 0
011
101
At last, sixth pixel is 1, surrounded by two 1, it stays 1
011
101
So, result is completely different from the expected result.
You get grid
011
101
Instead of grid
010
010
That is not directly the answer to your question. It is the answer to "why can't I just compute using a single grid, and why I need to compute a next_grid from a current_grid".
And my answer shows that you need to compute a new grid from a current grid.
Now, you have two options to do so.
Either at each step you allocate and compute a new grid, that, once computed becomes the current grid, and the former current grid is simply forgotten. That force you to redo the next_grid_model = [0] * height and for i in range(height): next_grid_model[i] = [1] * width each time. But it would work
Or, you don't want to bother creating a brand new next_grid_model at each step. So you just reuse the grid_model variable, that still exists, and whose, after all, you don't need any more, since you intend to replace it by next_grid_model.
That is the reason for the swap:
next_grid_model becomes grid_model, because, that is the game (I take you get that part. Again, from the first part of my answer, you probably understand why we need to compute a next_grid_model instead of updating grid_model directly. But then next_grid_model, as its name indicate, becomes the new grid_model.
And we need to create a new 2d-array to be the new next_grid_model. And if we don't want to create it from scratch, one solution is to say that the old grid_model will host the future next_grid_model. Hence the swap.
Note that such a trick is more important in other languages than in python. In C, for example, to allocate both grid, we would have to call malloc.
And calling malloc to create a new grid at each stage, while calling free on the former grids is a little bit stupid (allocating exactly the same amount of memory we are freeing — without free, it is even worse, and a memory leak). So it is quite classical in such case, to swap the "current" and "future" memories, instead of allocating a new one each time.
In python, if you were to just create a new next_grid_model each time, it would also work. Garbage collector would take care of all the former grids that you dropped, and everything would be fine. But even if it would work, that still would mean that you have to to the job of creating a new next_grid_model each time.
So a shorter answer could have been:
at each stage you need either to
next_grid_model = [0] * height
for i in range(height):
next_grid_model[i] = [1] * width
Or to
# Just a swap (I write it that way, because it is more compact,
# but it is the same thing as your 3 lines involving a temp variable)
next_grid_model, grid_model = grid_model, next_grid_model
Both works. They are just two way to create a future next_grid_model. Swap is simply faster.

How can I draw a pattern without using any third party libraries, and the sequence of input

I need to draw a pattern in the image given below without using any libraries in python.
Input: 3 4 3 4 5 1 9 2 2 4
Image:
Below is the code i tried but it does not working
def triangle(*args):
main=[]
for num in range(len(args)):
k = args[num] - 1
patt = []
for i in range(0, args[num]):
hello = ''
for j in range(0, k):
hello = hello + " "
if num%2==0:
k = k - 1
hello = hello+"/"
else:
k = k+ 1
hello = hello + "\\"
patt.append(hello)
main.append(patt)
return main
lists = triangle(3,4,3)
I don't know if I understand your question, but you could print it to the terminal without any modules.
In order to fit in bigger figures, you have to modify the length and amount of the rows. The lines don't connect perfectly, but you can definitely see the graph.
number_input = [4, 3, 2, 2, 5]
# default pattern
pattern = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
height = 5 # starting row (adaptable)
rows = 14 # rows of the pattern
lines = 0 # lines added to the pattern
def figure(height, lines, nums):
print(nums)
for i in range(len(nums)):
# if i is even it adds '/'
if i % 2 == 0:
for j in range(nums[i]):
pattern[rows-height-1][lines] = '/'
height += 1 # increase height by 1
lines += 1 # count the lines added to the pattern
height -= 1
# if i is odd it adds '\'
elif i % 2 == 1:
for j in range(nums[i]):
pattern[rows-height-1][lines] = '\\'
height -= 1 # decrease height by 1
lines += 1
height += 1
figure(height, lines, number_input)
# replace zeros with spaces
for line in pattern:
for i, num in enumerate(line):
if num == 0:
line[i] = ' '
# print the lines
print(*line)
Hope I could help.

am trying to convert this for loop into list comprehension?

L=[]
for i in range(11):
L.append(1)
for z in range(i):
L.append(0)
L.append(1) #this is to add a 1 at the end of list
print(L)
This should give the desired result - for i in the desired range, generate the tuple (1,0,0,0...) and then flatten the list of tuples. Finally, append the trailing 1.
>>> [x for i in range(11) for x in (1,)+(0,)*i] + [1]
[1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]

How to compare the values of same index in multiple list and print the start time and end time if condition not satisfy?

Here, i have 6 lists, all of them has same length of data. one is time which contains time from one start point to one end point and another five list contains signals.
time = [11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67]
A = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
B = [0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2]
C = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
D = [0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2]
E = [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
Here first i want to compare list A and B. if in list A 0 comes and in the same index 2 comes in B and if it is True then in second condition check in the same index in other three list there C should be 0, D should be 0 and E should be 1. if this condition satisfy then it is passed but in case in some point it comes different value then i need the start time and end time.
or j in range(len(time)):
lis = []
lis2 = []
for i in range(len(A)):
if(A[i] == 0 and B[i] == 2):
if C == 0 and D == 0 and E == 1:
lis.append(time[i])
else:
lis2.append(time[i])
print lis
print lis2
Using this code i've got the time where it is not satisfying but this isn't what i want.
i want the start time and end time like this
OUTPUT - [33,42] or [33,34,35,36,37,38,39,40,41,42]
Because in this time period 1st condition is True and from where it fails 2nd condition from there it should print the time till 1st condition True like i've given in output, then no need to check further.
Thank You In Advance.
I think this is what you want.
or j in range(len(time)):
lis = []
lis2 = []
bool = false
for i in range(len(A)):
if bool:
break
if(A[i] == 0 and B[i] == 2):
if C == 0 and D == 0 and E == 1:
lis.append(time[i])
else:
bool = true
lis2.append(time[i])
print lis
print lis2
Using numpy, you can do the following:
import numpy as np
A = np.array(A)
B = np.array(B)
C = np.array(C)
D = np.array(D)
E = np.array(E)
time = np.array(time)
print time[(A == 0)*(B == 2)*(C == 0)*(D == 0)*(E == 1)]
By the way, your example is wrong. The correct result is [32, 34, 35, 36, 37, 39, 40, 48, 49, 50, 51, 52], thus there are two periods with the correct pattern (from 31 to 40 and from 48 to 52).

Indexing 2 dimensional array in python

I've been trying to change a single item in a 2-dimensional array in python using the syntax x[2][3]=1 but instead of just changing the item in the 2nd row 3rd column, it ends up changing the values of all of the 3rd column. My code is below:
population = [[0]*20]*5
population[2][3] = 1
for row in population:
print(row)
This outputs
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
but I only want
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
How would I index the item such that it only changes the 2nd row and 3rd column?
I'm using python 3.7.4 on repl.it
Link here: https://repl.it/#ajqe/2d-array-test
Use :
population = [[0]*20 for _ in range(5)]
to generate the lists instead. The method you are using is referencing the same object 5 times, instead of creating 5 separate lists. To check this you can use the is operator:
>>> population = [[0]*20]*5
>>> population[0] is population[1]
True
>>> population = [[0]*20 for _ in range(5)]
>>> population[0] is population[1]
False

Categories

Resources