Multiple function calls for parallel processing inside a loop - multiprocessing

I wish to detect an image from my webcam and write the result whether it is moving left or right to a file. To increase the frame rate(because this project involves a lot more processing and might be run on a raspberry pi) I decided to do the file writing part through multiprocessing (which I am new to):
code:
function for multi-processing
def send_cmd(cv):
# ####EXECUTE LOGIC AND CREATE COMMAND###
# writing to file
# just a sample command// change as will
dictionary = {'left': 0, 'right': 0, 'stop': 0}
if cv[0] == 'left':
dictionary['right'] = 1
else:
dictionary['left'] = 1
cmd = '{"left":' + str(dictionary['left']) + ',"right":' + str(dictionary['left'
]) + ',"stop":' + str(dictionary['left']) + '}'
print("command written: " + cmd)
f = open('command.txt', 'w')
f.write(cmd)
f.close()
Main code:
while True:
try:
frame = cv.VideoCapture(0)
frame = imutils.resize(frame, width=400)
if W is None or H is None:
(H, W) = frame.shape[:2]
blob = cv.dnn.blobFromImage(cv.resize(frame, (300, 300)),
0.007843, (300, 300), 127.5)
net.setInput(blob)
detections = net.forward()
rects = []
for i in range(0, detections.shape[2]):
if detections[0, 0, i, 2] > args['confidence']:
box = detections[0, 0, i, 3:7] * np.array([W, H, W, H])
rects.append(box.astype('int'))
(startX, startY, endX, endY) = box.astype('int')
cv.rectangle(frame, (startX, startY), (endX, endY), (0,
0xFF, 0), 2)
objects = ct.update(rects)
for (objectID, centroid) in objects.items():
text = 'ID {}'.format(objectID)
cv.putText(
frame,
text,
(centroid[0] - 10, centroid[1] - 10),
cv.FONT_HERSHEY_SIMPLEX,
0.5,
(0, 0xFF, 0),
2,
)
cv.circle(frame, (centroid[0], centroid[1]), 4, (0, 0xFF,
0), -1)
center = (centroid[0], centroid[1])
pts.appendleft(center)
for i in np.arange(1, len(pts)):
if pts[i - 1] is None or pts[i] is None:
continue
if counter >= 10 and i == 1 and pts[-1] is not None:
dX = pts[-1][0] - pts[i][0]
dY = pts[-1][1] - pts[i][1]
global dirX
global dirY
(dirX, dirY) = ('', '')
if np.abs(dX) > 20:
dirX = ('left' if np.sign(dX) == 1 else 'right')
if np.abs(dY) > 20:
dirY = ('up' if np.sign(dY) == 1 else 'down')
#tried multiprocessing with process method but to many process calls at the same time
order = multiprocessing.Process(target = send_cmd,args = ([dirX, dirY]))
order.start()
order.join()
# send_cmd(cv=[dirX, dirY], us=ultra_sonic)
if dirX != '' and dirY != '':
direction = '{}-{}'.format(dirY, dirX)
else:
direction = (dirX if dirX != '' else dirY)
thickness = int(np.sqrt(args['buffer'] / float(i + 1))
* 2.5)
cv.putText(
frame,
direction,
(10, 30),
cv.FONT_HERSHEY_SIMPLEX,
0.65,
(0, 0, 0xFF),
3,
)
cv.putText(
frame,
'dx: {}, dy: {}'.format(dX, dY),
(10, frame.shape[0] - 10),
cv.FONT_HERSHEY_SIMPLEX,
0.35,
(0, 0, 0xFF),
1,
)
cv.imshow('Frame', frame)
key = cv.waitKey(1) & 0xFF
counter += 1
Error:
RuntimeError:
An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.
This probably means that you are not using fork to start your
child processes and you have forgotten to use the proper idiom
in the main module:
if __name__ == '__main__':
freeze_support()
...
The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce an executable.
Can someone guide me?

Related

Pygame sprite hitboxes don't follow as screen scrolls/zooms

First, the CameraGroup class is attributed to the wonderful youtube channel Clear Code.
Second, the hitboxes will not zoom (mousewheel) or scroll (WASD keys) with the planet icons. Try clicking the planets before zooming or scrolling and you will see the hitbox in action.
Third, as the screen is zoomed out the planets get smaller and the camera window shrinks towards the middle of the screen. Ideally, the camera window should stay the full size of the parent window to allow displaying more planets in the zoomed out state.
Finally, I am eager to learn, so please be brutal. Just drop the two planet icons in the folder with the .py file.
import os
import pygame
from pygame import *
from sys import exit
class CameraGroup(pygame.sprite.Group):
def __init__(self):
super().__init__()
self.display_surf_foreground = pygame.display.get_surface()
# camera offset
self.offset = pygame.math.Vector2()
self.half_w = self.display_surf_foreground.get_size()[0] // 2
self.half_h = self.display_surf_foreground.get_size()[1] // 2
self.scroll_offset = (0, 0)
# box setup
self.camera_borders = {'left': 200, 'right': 200, 'top': 100, 'bottom': 100}
l = self.camera_borders['left']
t = self.camera_borders['top']
w = self.display_surf_foreground.get_size()[0] - (self.camera_borders['left'] + self.camera_borders['right'])
h = self.display_surf_foreground.get_size()[1] - (self.camera_borders['top'] + self.camera_borders['bottom'])
self.camera_rect = pygame.Rect(l, t, w, h)
# camera speed
self.keyboard_speed = 10
# zoom
self.zoom_scale = 1
self.foreground_surf_size = (400, 400)
self.foreground_surf = pygame.Surface(self.foreground_surf_size, pygame.SRCALPHA)
self.foreground_rect = self.foreground_surf.get_rect(center=(self.half_w, self.half_h))
self.foreground_surf_size_vector = pygame.math.Vector2(self.foreground_surf_size)
self.foreground_offset = pygame.math.Vector2()
self.foreground_offset.x = self.foreground_surf_size[0] // 2 - self.half_w
self.foreground_offset.y = self.foreground_surf_size[1] // 2 - self.half_h
# planets and labels
self.planet_surf = pygame.Surface
self.planet_rect = pygame.Rect
def keyboard_control(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
self.camera_rect.x -= self.keyboard_speed
if keys[pygame.K_d]:
self.camera_rect.x += self.keyboard_speed
if keys[pygame.K_w]:
self.camera_rect.y -= self.keyboard_speed
if keys[pygame.K_s]:
self.camera_rect.y += self.keyboard_speed
self.offset.x = self.camera_rect.left - self.camera_borders['left']
self.offset.y = self.camera_rect.top - self.camera_borders['top']
def zoom_keyboard_control(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_q]:
self.zoom_scale += 0.1
if self.zoom_scale > 2:
self.zoom_scale = 2
if keys[pygame.K_e]:
self.zoom_scale -= 0.1
if self.zoom_scale < .5:
self.zoom_scale = .5
def custom_draw(self, planets):
self.keyboard_control()
self.zoom_keyboard_control()
self.foreground_surf.fill((0, 0, 0, 255))
# active elements
for planet in planets:
self.planet_surf = pygame.image.load(planet.icon).convert_alpha()
offset_coord = planet.coord - self.offset + self.foreground_offset
self.planet_rect = self.planet_surf.get_rect(center=offset_coord)
self.foreground_surf.blit(self.planet_surf, self.planet_rect)
scaled_surf = pygame.transform.scale(self.foreground_surf, self.foreground_surf_size_vector * self.zoom_scale)
scaled_rect = scaled_surf.get_rect(center=(self.half_w, self.half_h))
self.display_surf_foreground.blit(scaled_surf, scaled_rect)
class Game:
def __init__(self):
self.game_over = False
self.game_year = 0
self.game_state = 'splash'
#staticmethod
def activate_planet(screen, planets):
active_planet_coord = None
for planet in planets:
if planet.rect.collidepoint(pygame.mouse.get_pos()):
active_planet_coord = planet.rect.center
return active_planet_coord
return active_planet_coord
#staticmethod
def heartbeat(screen, active_planet_coord):
# global heartbeat_mod
global heartbeat
ticks = pygame.time.get_ticks()
heartbeat_thump = round(ticks / 1000) % 2
if heartbeat_thump == 0:
heartbeat_mod = .1
else:
heartbeat_mod = -.1
heartbeat += heartbeat_mod
if heartbeat < 1:
heartbeat = 1
elif heartbeat > 6:
heartbeat = 6
heartbeat_color = (0, 255, 0)
pygame.draw.circle(screen, heartbeat_color, active_planet_coord, 25 + round(heartbeat), round(heartbeat) + 2)
class Planet(pygame.sprite.Sprite):
def __init__(self, icon, group):
super().__init__(group)
self.icon = icon
self.coord = (0, 0)
self.group = group
self.image = pygame.image.load(self.icon).convert_alpha()
self.rect = self.image.get_rect(center=self.coord)
self.planet_icons = []
self.planet_names = []
#staticmethod
def update_coords(planets, star_coords):
i = 0
for planet in planets:
planet.coord = tuple(star_coords[i])
planet.rect = planet.image.get_rect(center=planet.coord)
i += 1
if i == len(star_coords):
del planets[len(star_coords):]
return planets
def main():
global heartbeat
global heartbeat_mod
pygame.init()
width, height = 400, 400
screen = pygame.display.set_mode((width, height))
pygame.display.init()
pygame.display.update()
active_planet_coord = (-100, -100)
heartbeat = 0
heartbeat_mod = .1
clock = pygame.time.Clock()
game = Game()
camera_group = CameraGroup()
planet_array = os.listdir('./')
planet_array.pop(0) # remove 'camera scroll example.py' file
planet_icons = planet_array
planets = []
for new_planet in range(2):
icon = planet_icons.pop()
planet = Planet(icon, camera_group)
planets.append(planet)
star_coords = [[100, 100], [200, 200]]
planets = planet.update_coords(planets, star_coords)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
pygame.quit()
exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
active_planet_coord = game.activate_planet(screen, camera_group)
if active_planet_coord is None:
active_planet_coord = (-100, -100)
pygame.display.update()
elif event.type == pygame.MOUSEWHEEL:
camera_group.zoom_scale += event.y * 0.1
if camera_group.zoom_scale > 2:
camera_group.zoom_scale = 2
elif camera_group.zoom_scale < .5:
camera_group.zoom_scale = .5
camera_group.update()
camera_group.custom_draw(planets)
game.heartbeat(screen, active_planet_coord)
pygame.display.update()
clock.tick(60)
if __name__ == '__main__':
main()
An alternative way to solve this problem is to "inverse zoom" the mouse position when you use it for click detection:
zoom:
p_zoom = (p - zoom_center) * zoom_scale + zoom_center
inverse zoom:
p = (p_zoom - zoom_center) / zoom_scale + zoom_center
Apply this to your code:
class Game:
# [...]
#staticmethod
def activate_planet(screen, planets):
zoom_scale = planets.zoom_scale
zoom_center = pygame.math.Vector2(screen.get_rect().center)
pos = pygame.math.Vector2(pygame.mouse.get_pos())
pos = (pos - zoom_center) / zoom_scale + zoom_center
active_planet_coord = None
for planet in planets:
if planet.rect.collidepoint(pos):
planet_center = (planet.rect.center - zoom_center) * zoom_scale + zoom_center
active_planet_coord = round(planet_center.x), round(planet_center.y)
return active_planet_coord
return active_planet_coord

pygame random points function

im trying to create a function that fill the screen with dots(that will be the points in the game)
the problem is the points created by a for loop and when i run the program the points just move around and wont stay in place.
the code:
def random_points():
point_x = random.randint(0, 900)
point_y = random.randint(0, 500)
rand_color = (random.random(), random.random(), (random.random()))
R = random.randint(1, 4)
for _ in range(1, 5):
pygame.draw.circle(WIN, rand_color, (point_x, point_y), R)
You need to create a list of points before the application loop:
point_list = []
for _ in range(1, 5):
point_x = random.randint(0, 900)
point_y = random.randint(0, 500)
rand_color = (random.random(), random.random(), (random.random()))
R = random.randint(1, 4)
point = (rand_color, (point_x, point_y), R)
point_list.append(point)
Draw the points from the list in the application loop:
run = True
while run:
for event = pygame.event.get():
if event.type == pygame.QUIT:
run = False
WIN.fill(0)
for color, center, rad in point_list:
pygame.draw.circle(WIN, color, center, rad)
pygame.disaply.flip()

Trapping Rain Water(algorithm)

That is a question at leetcode website.
https://leetcode-cn.com/problems/trapping-rain-water/
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.
I wrote the solution below.
int solution(vector<int>& height) {
int total = 0;
for (auto pos = height.begin(); pos != height.end(); pos++) {
if (*pos <= *(pos + 1))
continue;
for (auto lmaxpos = pos; *pos >= *(pos + 1); pos++) {
total = total + *lmaxpos - *(pos + 1);
for (; *(pos + 1) <= *lmaxpos; pos++) {
total = total + *lmaxpos - *(pos + 1);
if (*pos >= *(pos + 1)) {
total = total - (lmaxpos - pos) * (*lmaxpos - *pos);
break;
}
break;
}
break;
}
}
return total;
}
But after testing, i find that i have made some logical mistakes and i cann't find it out.
kindly ask you for help.
Traverse the array from both directions, storing the max_height seen so far. Now for each index, the water at that index is max(0, min(left_max, right_max) - cur_height).
E.g.,
input: [0,1,0,2,1,0,1,3,2,1,2,1]
max_from_left: [0,1,1,2,2,2,2,3,3,3,3,3]
max_from_right: [3,3,3,3,3,3,3,3,2,2,2,1]
water: [0-0, 1-0, 2-2, 2-1, 2-0, 2-1, 3-3, 2-2, 2-1, 2-2, 1-1]
water: [0, 1, 0, 1, 2, 1, 0, 0, 1, 0, 0]
sum(water) = 6
Here is a commented/explained solution.
Find maximum height of bar from the left end upto an index i in the array \text{left_max}left_max.
Find maximum height of bar from the right end upto an index i in the array \text{right_max}right_max.
Iterate over the \text{height}height array and update ans
from typing import List
def trapping_water_container(list: List) -> int:
l = 0
r = len(list) - 1
total, maxL, maxR = 0, 0, 0
while l < r:
# Identify the pointer with the lesser value
if list[l] <= list[r]:
# Check if the value for the left
# pointer is smaller than MaxLeft
if list[l] < maxL:
# Calculate the volume for this pointer
total += maxL - list[l]
else:
# Update the MaxLeft
maxL = list[l]
l += 1
else:
# Check if the value for the right
# pointer is smaller than MaxRight
if list[r] < maxR:
# Calculate the volume for this pointer
total += maxR - list[r]
else:
# Update the MaxRight
maxR = list[r]
r -= 1
return total

(Scala) Leetcode 200. Memory limit exceeded

I am using Scala to solve the problem documented here: https://leetcode.com/problems/number-of-islands/
Given a 2d grid map of '1's (land) and '0's (water), count the number
of islands. An island is surrounded by water and is formed by
connecting adjacent lands horizontally or vertically. You may assume
all four edges of the grid are all surrounded by water.
Example 1:
Input:
grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"] ]
Output: 1
Example 2:
Input:
grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"] ]
Output: 3
I thought it was a simple application of Breadth (or depth) First Search. However, my program produces a Memory Limit Exceeded error at Leetcode. I also ran the program on my laptop. My Mac reports it uses more than 3 GB memory, even if I'd commented out 3 lines of the test case. What consumes so much memory in my code?
// Memory OVERFLOW !!? Why ??
class Leet0200 {
def numIslands(grid: Array[Array[Char]]): Int = {
var (y, x) = getPosition(grid)
var c = 0
val dirs = Array(
Array(1, 0),
Array(-1, 0),
Array(0, 1),
Array(0, -1)
)
while ((y, x) != (-1, -1)) {
c += 1
val queue = scala.collection.mutable.Queue[(Int, Int)]()
queue.enqueue((y,x))
while (queue.nonEmpty) {
val me = queue.dequeue()
val (me_y, me_x) = me
grid(me_y)(me_x) = 'c'
for (d <- dirs) {
val (ny, nx) = (me_y + d(0), me_x+d(1))
if (ny >= 0 && ny < grid.length
&& nx >= 0 && nx < grid(0).length
&& grid(ny)(nx) == '1') {
queue.enqueue((ny, nx))
}
}
}
val newPos = getPosition(grid)
y = newPos._1
x = newPos._2
}
c
}
def getPosition(grid: Array[Array[Char]]): (Int, Int) = {
for (y <- grid.indices) {
for (x <- grid(0).indices) {
if (grid(y)(x) == '1') return (y, x)
}
}
(-1, -1)
}
}
object Leet0200 {
def main(args: Array[String]): Unit = {
val leet = new Leet0200()
println(
leet.numIslands(Array(
Array('1','1','1','1','1','0','1','1','1','1','1','1','1','1','1','0','1','0','1','1'),
Array('0','1','1','1','1','1','1','1','1','1','1','1','1','0','1','1','1','1','1','0'),
Array('1','0','1','1','1','0','0','1','1','0','1','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','0','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','0','0','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','0','1','1','1','1','1','1','0','1','1','1','0','1','1','1','0','1','1','1'),
Array('0','1','1','1','1','1','1','1','1','1','1','1','0','1','1','0','1','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','0','1','1','1','1','0','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','0','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('0','1','1','1','1','1','1','1','0','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','1','0','1','1','1','1','1','1','1','0','1','1','1','1','1','1'),
Array('1','0','1','1','1','1','1','0','1','1','1','0','1','1','1','1','0','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','0','1','1','1','1','1','1','0'),
//Array('1','1','1','1','1','1','1','1','1','1','1','1','1','0','1','1','1','1','0','0'),
//Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
//Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1')
)))
}
}
You will have duplicates in your queue and they will snowball. When you put stuff into the queue, check if it's already in there by changing your queue to a Set.
For example, let's inspect a map:
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
Initially, getPosition() will return (0, 0).
0, 0: You will put into the queue: (0, 1) and (1, 0).
0, 1: You will put into the queue: (0, 2) and (1, 1). The queue now has: (1, 0), (0, 2), (1, 1)
1, 0: You will put into the queue: (2, 0) and (1, 1). The queue now has: (0, 2), (1, 1), (2, 0), (1, 1)
Note that there are now 2 x (1, 1) in the queue. Thus (1, 1) will be processed twice, hence adding 2 x the results to the queue (i.e. 2 x (2, 1) and 2 x (1, 2)). These results will duplicate into 4 x (2, 2). Hence a snowball effect.
This will be the snowball effect consuming memory in your queue. If you use a Set, then you won't have the snowball effect as the same position will not get added again.
An alternate solution is to use your marker when adding to the queue instead of when processing like the code below:
val queue = scala.collection.mutable.Queue[(Int, Int)]()
queue.enqueue((y,x))
grid(y)(x) = 'c'; // <--- moved to
while (queue.nonEmpty) {
val me = queue.dequeue()
val (me_y, me_x) = me
// grid(me_y)(me_x) = 'c' // <--- moved from
for (d <- dirs) {
val (ny, nx) = (me_y + d(0), me_x+d(1))
if (ny >= 0 && ny < grid.length
&& nx >= 0 && nx < grid(0).length
&& grid(ny)(nx) == '1') {
queue.enqueue((ny, nx))
grid(ny)(nx) = 'c'; // <--- moved to
}
}
}
Because you do the grid(ny)(nx) == '1' check, the same position will not be added to the queue multiple times.

logical matrix how to find efficiently row/column with true value

I'm trying to find a efficient solution for the next riddle:
i have a logical matrix at (n * n) size filled in false values
i need to create a function that will get zero or one as argument it will shift all
the values in the matrix one step to the left (meaning the first
element on the first row is deleted and the last element in the last
row is our new bit) and return true if there is a row/column in our
matrix contains only one's values.
No limitation on the data structure.
My naive solution in javascript:
const next = (bit, matrix) => {
matrix.shift()
matrix.push(bit);
const matrix_size = Math.sqrt(matrix.length);
let col_sum = 0;
let row_sum = 0;
for (let i = 0; i < matrix.length; ++i) {
col_sum = matrix[i];
row_sum += matrix[i];
if ((i + 1) % matrix_size === 0) {
if (row_sum === matrix_size) return true;
row_sum = 0;
}
for (let j = i + matrix_size;j < (i + ((matrix_size * matrix_size) - 1)); j += matrix_size) {
col_sum += matrix[j];
}
if (col_sum === matrix_size) return true;
}
return false;
}
i used 1d array as data structure but it doesn't really help my to reduce time complexity.
Love to hear some ideas :)
Let’s think about following example matrix:
[0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 1, 1,
1, 1, 1, 1]
and push zero 16 times.
Then, False, True, True, True, False, True, True, True, False, True, True, True, False, False False and False will be obtained.
There is cyclic behavior (False, True, True, True).
If the length of continued ones was fixed, it isn’t necessary to recalculate every time in update.
Updated the matrix, the length of continued ones at top-left and bottom-right can be change, and it can be needed to update the cyclic memory.
Maintaining continued ones sequences, maintaining total count of cyclic behavior affected by the sequences, the complexity for the rows will be in O(1).
In case of column, instead of shifting and pushing, let matrix[cur]=bit and cur = (cur+1)%(matrix_size*matrix_size) to represent cur as the actual upper-left of the matrix.
Maintaining col_sum of each column, maintaining total count satisfying the all-ones-condition, the complexity will be O(1).
class Matrix:
def __init__(self, n):
self.mat = [0] * (n*n)
self.seq_len = [0] * (n*n)
self.col_total = [0] * n
self.col_archive = 0
self.row_cycle_cnt = [0] * n
self.cur = 0
self.continued_one = 0
self.n = n
def update(self, bit):
prev_bit = self.mat[self.cur]
self.mat[self.cur] = bit
# update col total
col = self.cur % self.n
if self.col_total[col] == self.n:
self.col_archive -= 1
self.col_total[col] += bit - prev_bit
if self.col_total[col] == self.n:
self.col_archive += 1
# update row index
# process shift out
if prev_bit == 1:
prev_len = self.seq_len[self.cur]
if prev_len > 1:
self.seq_len[(self.cur + 1) % (self.n * self.n)] = prev_len-1
if self.n <= prev_len and prev_len < self.n*2:
self.row_cycle_cnt[self.cur % self.n] -= 1
# process new bit
if bit == 0:
self.continued_one = 0
else:
self.continued_one = min(self.continued_one + 1, self.n*self.n)
# write the length of continued_one at the head of sequence
self.seq_len[self.cur+1 - self.continued_one] = self.continued_one
if self.n <= self.continued_one and self.continued_one < self.n*2:
self.row_cycle_cnt[(self.cur+1) % self.n] += 1
# update cursor
self.cur = (self.cur + 1) % (self.n * self.n)
return (self.col_archive > 0) or (self.row_cycle_cnt[self.cur % self.n] > 0)
def check2(self):
for y in range(self.n):
cnt = 0
for x in range(self.n):
cnt += self.mat[(self.cur + y*self.n + x) % (self.n*self.n)]
if cnt == self.n:
return True
for x in range(self.n):
cnt = 0
for y in range(self.n):
cnt += self.mat[(self.cur + y*self.n + x) % (self.n*self.n)]
if cnt == self.n:
return True
return False
if __name__ == "__main__":
import random
random.seed(123)
m = Matrix(4)
for i in range(100000):
ans1 = m.update(random.randint(0, 1))
ans2 = m.check2()
assert(ans1 == ans2)
print("epoch:{} mat={} ans={}".format(i, m.mat[m.cur:] + m.mat[:m.cur], ans1))

Resources