How to find the largest sequence in binary array? - python

I'm trying to find the largest 1's secuence inside a random array.
I'm trying to find the longest connection of numbers 1 inside a binary array.
I tried to compare each value of the array with its previous values (i+-1 and j+-1), but I failed.
rows = 5
cols = 5
matrix = np.random.randint(2, size=(rows, cols))
print(matrix)
count = 0
result = 0
for i in matrix:
for j in i:
if j <= cols and j <= len(i):
if j == 1:
count += 1
result = max(result, count)
else:
count = 0
print(result)
This is an example of a random array given in my code
matrix =
[[1 1 0 1 1]
[1 0 0 0 1]
[1 1 1 1 1]
[0 0 1 0 0]
[1 0 1 0 0]]
Once we have found the largest conection of numbers 1, the result will be like that:
matrix =
[[(1) (1) 0 (1) (1)]
[(1) 0 0 0 (1)]
[(1) (1) (1) (1) (1)]
[ 0 0 (1) 0 0]
[ 1 0 (1) 0 0]]
The numbers inside the parentheses, those are the largest conection and the result would be like this:
result = 13
Complete Code
import numpy as np
rows = 200
cols = 200
arr = np.random.rand(rows, cols)
for i in range(len(arr)):
for j in range(len(arr[i])):
if arr[i][j] > 0.4:
arr[i][j] = 1
else:
arr[i][j] = 0
for ii in range(len(arr)):
for jj in range(len(arr[ii])):
if arr[ii][jj] == 1.0 or arr[ii][jj] == 1:
arr[ii][jj] = 1
else:
arr[ii][jj] = 0
arr = arr.astype(int)
print(arr)
dimension = rows * cols
danger = eval("dimension * .0002")
def find_largest(arr):
max_count = 0
visited = set() # coordinates visited by DFS
for y in range(0, len(arr)):
for x in range(0, len(arr[y])):
if arr[y][x] == 1 and (y, x) not in visited:
# Runs DFS search on (y,x) and marks cell as visited
max_count = max(max_count, explore(arr, y, x, visited))
probable_danger = suma(max_count)
print("Quantity of connections: " + str(max_count) +
" ,probability of danger: " + str(probable_danger) + " ,comparing to the total; " +
str(danger))
return max_count
def explore(arr, y, x, visited):
if arr[y][x] == 1 and (y, x) not in visited:
count = 1
visited.add((y, x))
for i, j in adj(arr, y, x):
count += explore(arr, i, j, visited)
return count
else:
return 0
def adj(arr, y, x):
# Generates valid adjacent coordinates for (y, x)
if y - 1 > 0 and arr[y - 1][x] == 1:
yield y - 1, x
if y + 1 < len(arr) and arr[y + 1][x] == 1:
yield y + 1, x
if x - 1 > 0 and arr[y][x - 1] == 1:
yield y, x - 1
if x + 1 < len(arr[y]) and arr[y][x + 1] == 1:
yield y, x + 1
def suma(max_count):
dimension = rows * cols
danger = eval("dimension * .0002")
total_ones = 0
total_zeros = 0
for i in arr:
for j in i:
if j % 2 != 0:
total_ones += 1
else:
total_zeros += 1
found = max_count / total_ones
ones = total_ones/dimension
zeros = total_zeros/dimension
print("Total of 1's "+str(ones) +
" , total of 0's: "+str(zeros))
if (found >= danger):
return found
else:
return 0
find_largest(arr)

You can look at groups of 1s in your matrix as strongly connected components in a graph. You can solve this problem using DFS.
def find_largest(arr):
max_count = 0
visited = set() # coordinates visited by DFS
for y in range(0, len(arr)):
for x in range(0, len(arr[y])):
if arr[y][x] == 1 and (y, x) not in visited:
# Runs DFS search on (y,x) and marks cell as visited
max_count = max(max_count, explore(arr, y, x, visited))
return max_count
Now on DFS itself:
def explore(arr, y, x, visited):
if arr[y][x] == 1 and (y, x) not in visited:
count = 1
visited.add((y, x))
for i, j in adj(arr, y, x):
count += explore(arr, i, j, visited)
return count
else:
return 0
def adj(arr, y, x):
# Generates valid adjacent coordinates for (y, x)
if y - 1 > 0 and arr[y - 1][x] == 1:
yield y - 1, x
if y + 1 < len(arr) and arr[y + 1][x] == 1:
yield y + 1, x
if x - 1 > 0 and arr[y][x - 1] == 1:
yield y, x - 1
if x + 1 < len(arr[y]) and arr[y][x + 1] == 1:
yield y, x + 1

Related

Print nxn grid clockwise and print the sum of the diagonal elements

Example if n = 5 it should print
21 22 23 24 25
20 7 8 9 10
19 6 1 2 11
18 5 4 3 12
17 16 15 14 13
Sum = 21+7+1+3+13+17+5+9+25
= 101
Here is my code
dim=5
result= n = 1
for in range(2,dim,2):
for i in range(4):
n+=k
result+=n
print(result)
Here is what I made
def spiral(n):
# Initialize the values
m = [[0]*n for _ in" "*n] # Define a list of list of n dim
d = n
v = n*n # values
y = 0 # cord of y
x = n # cord of x
while d > 0:
for _ in" "*d: # Equivalent to <=> for i in range(d)
x -= 1
m[y][x] = v
v-=1
d -= 1
for _ in" "*d:
y += 1
m[y][x] = v
v-=1
for _ in" "*d:
x += 1
m[y][x] = v
v-=1
d -= 1
for _ in" "*d:
y -= 1
m[y][x] = v
v-=1
return m # return the list of list
n = 5
matrix = spiral(n)
# Print lines of the matrix
print("Matrix:")
for e in matrix:
print(*e)
# Print the sum
print(f"Sum: {sum(matrix[i][i]for i in range(n)) + sum(matrix[i][n - i - 1]for i in range(n)) - 1}") # There is a - 1 at the end, because the value of the middle is 1
You can rewrite the while loop like this:
while d > 0:
for i in range(4):
for _ in" "*d:
if i%2:
y -= 2 * (i==3) - 1
else:
x -= 2 * (i==0) - 1
m[y][x] = v
v-=1
if i%2 == 0:
d -= 1
It's shorter but less easy to understand
You can compute The Sum this way
def Spiral(size: int):
if(size<=1):
return 1
else:
Sum = 4*(size)**2 - 6(size-1)
return (Sum+Spiral(size-2))
Spiral(5)

Converting "for loop" to "while loop" in python

I am trying to convert the code by replacing for loop with while loop.
This is the code which I want to be converted
Functions for the code in the below snippet. Asked by #Sameer
from random import sample
def shuffle(s): return sample(s,len(s))
rBase = range(base)
base = 2
side = base*base
def pattern(r,c):
return (base*(r%base)+r//base+c)%side
Code in which I have the problem
rows = []
cols = []
data = []
for r in shuffle(rBase):
for g in shuffle(rBase):
rows.append(g*base+r)
for c in shuffle(rBase):
for g in shuffle(rBase):
cols.append(g*base+c)
nums = shuffle(range(1,side+1))
for r in rows:
for c in cols:
data.append(nums[pattern(r,c)])
Here is my attempted code
rows = []
cols = []
data = []
s = shuffle(rBase)
i,j = 0,0
while i < len(s):
r = s[i]
while j < len(s):
s2 = shuffle(rBase)
g = s2[i]
rows.append(g*base+r)
j+=1
i += 1
i,j = 0,0
s = shuffle(rBase)
while i < len(s):
c = s[i]
while j < len(s):
s2 = shuffle(rBase)
g = s2[i]
cols.append(g*base+c)
j += 1
i += 1
nums = shuffle(range(1,side+1))
i,j =0,0
while i < len(rows):
r = rows[i]
while j < len(cols):
c = cols[i]
data.append(nums[pattern(r,c)])
j += 1
i += 1
Some part of the code is omitted due to privacy reasons.
Expected output, ie output of for loop snippet is a list with length (base ** 4) containing each number from 1 to base ** 2 exactly base ** 2 times.
For Eg:
if base is 2:
expected output would be like [3, 2, 1, 4, 4, 1, 3, 2, 1, 4, 2, 3, 2, 3, 4, 1]
Actual output is a list of length base with each element is a random number between 1 and base ** 2.(Including base ** 2)
For Eg:
if base is 2:
Actual output is like [1,1] or [2,2] or [3,3] or [4,4]
Variable j = 0 should be defined before the inner while loop. Currently, your inner while is running 'len(s)' times only also you are indexing with 'i' in your second loop, you should have used j there.
This Should Work
from random import sample
def shuffle(s): return sample(s,len(s))
base = 2
rBase = range(base)
side = base*base
def pattern(r,c):
return (base*(r%base)+r//base+c)%side
rows = []
cols = []
data = []
for r in shuffle(rBase):
for g in shuffle(rBase):
rows.append(g*base+r)
for c in shuffle(rBase):
for g in shuffle(rBase):
cols.append(g*base+c)
print(rows)
print(cols)
nums = shuffle(range(1,side+1))
for r in rows:
for c in cols:
data.append(nums[pattern(r,c)])
print(data)
rows = []
cols = []
data = []
s = shuffle(rBase)
s2 = shuffle(rBase)
i = 0
while i < len(s):
r = s[i]
j = 0
while j < len(s):
g = s2[j]
j = j + 1
rows.append(g*base+r)
i = i + 1
i = 0
s = shuffle(rBase)
s2 = shuffle(rBase)
while i < len(s):
c = s[i]
j = 0
while j < len(s):
g = s2[j]
cols.append(g*base+c)
j += 1
i += 1
nums = shuffle(range(1,side+1))
i =0
while i < len(rows):
r = rows[i]
j = 0
while j < len(cols):
c = cols[j]
data.append(nums[pattern(r,c)])
j += 1
i += 1
print(rows)
print(cols)
print(data)

What is wrong with my program? Amicable program

Question 3: Amicable
Implement a function amicable that takes a positive integer n. It returns the smallest amicable number greater than n.
Two different numbers are both amicable if the sum of the proper divisors of each is equal to the other. Any number that's part of such a pair is an amicable number.
def abundant(n):
while n > 0:
a = n
k = n
y = 0
total = 0
while k > y or n == 0:
if n % k == 0:
y = n // k
if k != n:
total = total + k + y
if k == y:
total = total - y
k -=1
total = total + 1
print(total)
def abundant2(n):
b = n
x = n
y = 0
total2 = 0
while x > y or n == 0:
if n % x == 0:
y = n // x
if x != n:
total2 = total2 + x + y
if x == y:
total2 = total2 - y
x -=1
total2 = total2 + 1
print(total2)
if total == b and total2 == a:
print('Amicable!')
amicable_numbers2 = int(total2)
amicable_numbers = int(total)
else:
print('Nope')
return abundant2
n += 1
def amicable(n):
"""Return the smallest amicable number greater than positive integer n.
Every amicable number x has a buddy y different from x, such that
the sum of the proper divisors of x equals y, and
the sum of the proper divisors of y equals x.
For example, 220 and 284 are both amicable because
1 + 2 + 4 + 5 + 10 + 11 + 20 + 22 + 44 + 55 + 110 is 284, and
1 + 2 + 4 + 71 + 142 is 220
>>> amicable(5)
220
>>> amicable(220)
284
>>> amicable(284)
1184
>>> r = amicable(5000)
>>> r
5020
"""
nums = [amicable_numbers2, amicable_numbers]
nums2 = [n for n in nums if n >= amicable_numbers2 and n <= amicable_numbers]
return nums2
# return a value that is less than amicable_numbers2 and less than amicable_numbers???

Python, and The Game of Life Rules

Okay, so i finally get this to print, and actually do something, but the rules are not applying right? I've tried messing with the rules, but can't seem to get them to print out right, here's the snip of my rules:
nCount = 0
for i in range(x-1,x+2):
for j in range(y-1,y+2):
if not(i == x and j == y):
nCount += int(mat[i][j])
if(nCount < 2 or nCount > 3):
return 0
elif(nCount == 2 or nCount == 3):
return 1
else:
return mat[i][j]
I've tested with a regular 5x5 with 3 1's in the middle to act as an oscillator but instead of oscillating it fills the 5x5 edges with zeros like a square box then stops
Here is the rest of my coding:
import time
import os
def buildMatrix(fname):
fp = open(fname, "r")
row = fp.readlines()
matrix = []
for i in range(0, len(row), 1):
token = row[i].split(" ")
token[-1] = token[-1].replace('\n', ' ')
matrix.append(token)
fp.close()
return matrix
def getRows(mat):
return len(mat)
def getCols(mat):
return len(mat[0])
def printGen(mat): #this is what i use for printing
os.system('clear')
for i in range(0, len(mat), 1):
for j in range(0, len(mat[0]), 1):
if(mat[i][j] == 1):
print("#", sep=" ", end=" ")
else:
print(" ", sep=" ", end=" ")
print()
def nextGen(cur, nxt): #use this to update to the next matrix
for i in range(0, len(cur)-1, 1):
for j in range(0, len(cur[0])-1, 1):
nxt[i][j] = neighbors(i, j, cur)
return nxt
def neighbors(x, y, mat):
nCount = 0
for i in range(x-1,x+2):
for j in range(y-1,y+2):
if not(i == x and j == y):
nCount += int(mat[i][j])
if(nCount < 2 or nCount > 3):
return 0
elif(nCount == 2 or nCount ==3):
return 1
else:
return mat[i][j]
This isnt all my code, as im still importing all this to another repo and running it from that repo, but the other part i have done
elif(nCount == 2,3):
This doesn't do what you want. This builds a 2-element tuple whose first element is the value of nCount == 2, and whose second element is 3, then converts this tuple to a boolean to decide which way to go. If you wanted to check whether nCount was equal to either 2 or 3, you could use
elif nCount in (2, 3):
but it's redundant, since nCount must be one of those for control flow to reach the elif. Of course, this isn't correct for implementing the rules of Life; what you want is
elif nCount == 3:
A cell keeps its current live/dead status if surrounded by 2 other live cells. There have to be exactly 3 live cells around it for it to be alive in the next generation regardless of its current life status.
It looks like your code isn't making a copy first, so the results of a birth or death are effecting themselves. Try with a copy:
import numpy
# this function does all the work
def play_life(a):
xmax, ymax = a.shape
b = a.copy() # copy current life grid
for x in range(xmax):
for y in range(ymax):
n = numpy.sum(a[max(x - 1, 0):min(x + 2, xmax), max(y - 1, 0):min(y + 2, ymax)]) - a[x, y]
if a[x, y]:
if n < 2 or n > 3:
b[x, y] = 0 # living cells with <2 or >3 neighbors die
elif n == 3:
b[x, y] = 1 # dead cells with 3 neighbors ar born
return(b)
life = numpy.zeros((5, 5), dtype=numpy.byte)
# place starting conditions here
life[2, 1:4] = 1 # middle three in middle row to 1
# now let's play
print(life)
for i in range(3):
life = play_life(life)
print(life)
I also used numpy for speed. Note that the case for a live cell with 2 or 3 neighbors is taken care of when the copy is made. Here are the results of this test case:
[[0 0 0 0 0]
[0 0 0 0 0]
[0 1 1 1 0]
[0 0 0 0 0]
[0 0 0 0 0]]
[[0 0 0 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 0 0 0]]
[[0 0 0 0 0]
[0 0 0 0 0]
[0 1 1 1 0]
[0 0 0 0 0]
[0 0 0 0 0]]
[[0 0 0 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 1 0 0]
[0 0 0 0 0]]
Now, if you don't have numpy, then you can use a "2D" array like this:
# this function does all the work
def play_life(a):
xmax = len(a)
ymax = len(a[0])
b = [[cell for cell in row] for row in life]
for x in range(xmax):
for y in range(ymax):
n = 0
for i in range(max(x - 1, 0), min(x + 2, xmax)):
for j in range(max(y - 1, 0), min(y + 2, ymax)):
n += a[i][j]
n -= a[x][y]
if a[x][y]:
if n < 2 or n > 3:
b[x][y] = 0 # living cells with <2 or >3 neighbors die
elif n == 3:
b[x][y] = 1 # dead cells with 3 neighbors ar born
return(b)
# this function just prints the board
def show_life(a):
print('\n'.join([' '.join([str(cell) for cell in row]) for row in life]) + '\n')
# create board
x_size, y_size = (5, 5)
life = [[0 for y in range(y_size)] for x in range(x_size)]
# place starting conditions here
for x in range(1, 4): life[x][2] = 1 # middle three in middle row to 1
# now let's play
show_life(life)
for i in range(3):
life = play_life(life)
show_life(life)
That outputs the following for the test case:
0 0 0 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 1 1 1 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 1 1 1 0
0 0 0 0 0
0 0 0 0 0

Placing numbers around bombs in Minesweeper: why do I get "list index out of range"?

I have a function that places 'z' amount of bombs randomly scattered across a 10x10 grid. It looks something like this ("b" represents where the bombs are located.) I need to place a number representing how many bombs there are next to the "0" (including diagonals), and I am not sure how to do that.
0 0 0 0 0 0 0 0 b 0
b 0 0 b 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 b 0 0 0
0 0 0 b 0 0 0 0 0 0
0 0 b 0 0 0 0 0 0 b
0 0 0 0 0 0 0 b 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 b 0 b 0 0 0 0
0 0 0 0 0 0 0 0 0 0
from random import*
mat1 = []
mat2 = []
def makemat(x):
for y in range(x):
list1 = []
list2 = []
for z in range(x):
list1.append(0)
list2.append("-")
mat1.append(list1)
mat2.append(list2)
makemat(5)
def printmat(mat):
for a in range(len(mat)):
for b in range(len(mat)):
print(str(mat[a][b]) + "\t",end="")
print("\t")
def addmines(z):
count = 0
while (count < z):
x = randrange(0,len(mat1))
y = randrange(0,len(mat1))
if mat1[y][x] == "b":
count -= 1
else:
mat1[y][x] = "b"
count += 1
printmat(mat1)
addmines(10)
This is the function I tried for placing the numbers:
def addscores():
for x in range(len(mat1)):
for y in range(len(mat1)):
if mat1[y][x] != "b":
if mat1[y+1][x] == "b":
mat1[y][x] = 1
if mat1[y-1][x] == "b":
mat1[y][x] = 1 #...ETC
else:
mat1[y][x] == "b"
addscores()
I keep getting the error list index out of range. How can I resolve this?
Let's say that (x, y) = (9, 9), you get the IndexError because you do:
if mat1[y+1][x] == "b":
which tries to access the index mat1[10], which doesn't exists because your list is only 10 elements long.
Also, let's say that (x, y) = (0, 0). Then when you do:
if mat1[y-1][x] == "b":
You access the index mat[-1], which is equivalent to mat[9]. I'm pretty sure this is not what you intend.
There are 2 easy ways to correct this:
1) Include an additional set of if statements to ensure that you don't attempt to access list elements outside the bounds of the list:
Change:
if mat1[y+1][x] == "b":
mat1[y][x] = 1
if mat1[y-1][x] == "b":
mat1[y][x] = 1
To:
#parentheses in if statements added for clarity
if (y < len(mat1) - 1) and (mat1[y+1][x] == "b"):
mat1[y][x] = 1
if (y > 0) and (mat1[y-1][x] == "b"):
mat1[y][x] = 1
2) This is the method I prefer. Add a layer of "padding" around the array. When you first create your array, do:
WIDTH = 10
HEIGHT = 10
myMap = [[0 for i in range(WIDTH + 2)] for j in range(HEIGHT + 2)]
Then, when you access elements in your array, just make sure that you are indexing from 1, not 0:
#do this
firstElement = myMap[1][1]
#not this
firstElement = mayMap[0][0]
#do this
for i in range(1, len(myMap) - 1): pass
#not this
for i in range(len(myMap)): pass
change
if mat1[y+1][x] == "b":
to
if safeEquals(mat1, y+1, x, "b"):
and define safeEquals as
def safeEquals(mat, y, x, value):
try:
return mat1[y][x] == "b"
except IndexError as e:
return False
This essentially allows you to provide a default behaviour if you index outside the map position.
PS the code executed after the condition:
mat1[y][x] = 1
should be
mat1[y][x] += 1
as presence of an adjacent bomb increments the bomb counter (otherwise how does a 3 ever appear on the map_
An easy way to avoid the index errors is to use defaultdict to hold mat1 and mat2. As a bonus the code is shorter :)
from random import randrange
from collections import defaultdict
mat1 = defaultdict(int)
mat2 = defaultdict(lambda:"-")
size = 5
def printmat(mat):
for a in range(size):
print("\t".join(str(mat[a, b]) for b in range(size)))
def addmines(count):
while (count):
x = randrange(0,size)
y = randrange(0,size)
if mat1[y, x] != "b":
mat1[y, x] = "b"
count -= 1
printmat(mat1)
addmines(10)
def addscores():
for x in range(size):
for y in range(size):
if mat1[y, x] != "b":
if mat1[y+1, x] == "b":
mat1[y, x] = 1 # should be +=
if mat1[y-1, x] == "b":
mat1[y, x] = 1 #...ETC
else:
mat1[y, x] == "b"
addscores()
if y is in range(len(mat1)) then y+1 is not...

Categories

Resources