Computer Solving Lights On Game - python

I have made a game where a board of randomly lit squares are generated (0 is off and 1 is on) and the goal is to light up the entire board. Currently I have been using user input to win the game where when a square is clicked it inverts as well as its neighbors above, bellow, left, and right. Now I am trying to allow the computer to solve the game without user input, but my choice function in evolve2d does not work correctly. Currently it is producing the original list over and over again. Any guidance would be greatly appreciated.
import time # provides time.sleep(0.5)
from csplot import choice
from random import * # provides choice( [0,1] ), etc.
import sys # larger recursive stack
sys.setrecursionlimit(100000) # 100,000 deep
def runGenerations2d(L , x = 0,y=0):
show(L)
print( L ) # display the list, L
time.sleep(.1) # pause a bit
newL = evolve2d( L ) # evolve L into newL
print(newL)
if min(L) == 1:
#I like read outs to be explained so I added an extra print command.
if x<=1: # Takes into account the possibility of a 1 click completition.
print ('BaseCase Reached!... it took %i click to complete' % (x))
print (x)
done()#removes the need to input done() into the shell
else:
print ('BaseCase Reached!... it took %i clicks to complete' % (x))
print (x)
done()#removes the need to input done() into the shell
return
x = x+1 # add 1 to x before every recusion
runGenerations2d( newL , x,y ) # recurse
def setNewElement2d( L, i, j, x=0, y=0 ):
if y==j and (i == x-1 or i == x+1 or i ==x):
return 1-L[j][i]
elif x==i and (j == y-1 or j == y+1):
return 1-L[j][i]
else:
return L[j][i]
def evolve2d( L ):
N = len(L) # N now holds the size of the list
x = choice (L)
y = choice (L)
return [[ setNewElement2d( L, i, j,x,y ) for i in range(N)]for j in range(N) ]

Related

How can i optimize my sudoku generator code to generate sudoku puzzles faster

I modified the sudoku generator code I found at https://medium.com/codex/building-a-sudoku-solver-and-generator-in-python-1-3-f29d3ede6b23 to look like this:
def generateBoard():
print("Generating puzzle...please wait")
time.sleep(1)
gameboard = createEmpty() # creates a list with the three diagonal boxes filled and the rest filled with zeros
gameboard = solve(gameboard) # changes the unsolved board DIRECTLY to a solved board
gameboard = removeNumbers(gameboard,38)
print("\nHere's your puzzle :)")
printBoard(gameboard)
So what the above code does is, it first creates a list in which the three 3x3 subgrids in the leading diagonal are filled with numbers 1 through 9 (sudoku rules) using the createEmpty() function below:
def createEmpty():
board = [[0 for i in range(9)] for j in range(9)]
for i in range(3):
box = shuffle(range(1,10))
for y in range(i*3, i*3+3):
for x in range(i*3, i*3+3):
board[y][x] = box.pop()
return board
This function was only returning a 9x9 list filled with zeros (first line) before, but according to the article i read in that website, it said that using this method of filling the three boxes in the diagonal with numbers before solving would save some time in backtracking so i changed it and it affected the time spent but by only a little amount.
def solve(board):
empty = find_empty(board)
if not empty:
return True
col, row = empty
for num in shuffle(range(1,10)):
if valid(board, num, empty):
board[row][col] = num
if solve(board):
return board
board[row][col] = 0
return False
So after creating the list, it uses the solve() function above👆👆 which uses backtracking to solve the partially filled board.
So after getting a solved sudoku board, i created a function (removeNumbers) to remove numbers from the board to create the puzzle. The function and its dependent functions are below:
def removeNumbers(solvedboard,hints=None):
board = copy.deepcopy(solvedboard)
remaining = 81
if not hints: hints = random.randrange(28, 40)
for y in range(3):
for x in range(3):
boxCoords = [(i,j) for j in range(y*3, (y*3)+3) for i in range(x*3, (x*3)+3)]
for n in range(random.choice(range(1,5))):
a, b = random.choice(boxCoords)
board[b][a] = 0
boxCoords.remove((a,b))
remaining -= 1
coords = [(i,j) for i in range(9) for j in range(9)]
coords = list(filter(lambda p: board[p[0]][p[1]] != 0, coords))
random.shuffle(coords)
for row, col in coords:
if remaining == hints:
break
num = board[row][col]
board[row][col] = 0
n = numberOfSolutions(board, solvedboard)
if n != 1:
board[row][col] = num
continue
remaining -= 1
#printBoard(board)
#print(remaining, hints)
return board
def numberOfSolutions(board, solved=[], ret=False):
solutions = []
# find a solution in which an empty square has a valid value and add it to the list(solutions)
for row in range(9):
for col in range(9):
if board[row][col] == 0:
dupeBoard = copy.deepcopy(board)
solution = getSolution(dupeBoard, row, col)
if not ret and solution != solved:
return 0
if solution:
solutions.append(code(solution))
solutions = list(set(solutions))
return len(solutions) if not ret else solutions
def getSolution(board, row, col):
for n in range(1, 10):
# insert a valid number into the (row,col) and return a solved board or if there are no solutions for that board, return False
if valid(board, n, (col, row)):
board[row][col] = n
if (solvedboard:=solve(board)):
return solvedboard
board[row][col] = 0
return False
def valid(board, num, pos):
x, y = pos
# check rows
if board[y].count(num) > 0:
return False
# check columns
if [board[j][x] for j in range(9)].count(num) > 0:
return False
# 3x3 grid
grid_x, grid_y = x-(x % 3), y-(y % 3)
grid = [board[j][i] for j in range(grid_y, grid_y+3) for i in range(grid_x, grid_x+3)]
if grid.count(num) > 0:
return False
return True
The removeNumbers() function has a local variable hints which represents the number of clues present in the sudoku puzzle and which contains a random number from 28 to 40, with 28 being the hardest and 39 being the simplest.
After removing the numbers from the board, the resulting board is printed out using the printBoard() function below:
def printBoard(board):
print("-"*41)
for y in range(len(board)):
if y % 3 == 0:
print(('||'+'-'*11)*3, end='')
print('||')
print(f"|| {board[y][0] if board[y][0]!=0 else ' '} | {board[y][1] if board[y][1]!=0 else ' '} | {board[y][2] if board[y][2]!=0 else ' '} ||", end='')
print(f" {board[y][3] if board[y][3]!=0 else ' '} | {board[y][4] if board[y][4]!=0 else ' '} | {board[y][5] if board[y][5]!=0 else ' '} ||", end='')
print(f" {board[y][6] if board[y][6]!=0 else ' '} | {board[y][7] if board[y][7]!=0 else ' '} | {board[y][8] if board[y][8]!=0 else ' '} ||")
print(('||'+'-'*11)*3, end='')
print('||')
print('-'*41)
Right now my generator generates simple sudoku puzzles in 30+ seconds and hard sudoku puzzles in 3+ minutes. And the code in that website generates simple in 0.22 secs, medium in 2+ secs and hard in 20+ secs.
But after several debugging, I found out that a large amount of time is spent at the removeNumbers() function. Having said all of that, I'll appreciate it if you could help me to optimize the removeNumbers() function and therefore reduce the amount of time spent generating the sudoku puzzle.

Appearing animation for spiral matrix

I'm trying to make a spiral matrix, but when I tried to make the numbers appear one by one, it only shows the lines one by one.
Please help!
import numpy as np
from time import sleep
n = int(input("Width : "))
k = int(input("Space : "))
a = np.zeros((n,n))
print(a/n)
i = 0 #i line
j = 0 #j column
it = -1 #it upper line
id = n #id downer line
jt = -1 #jt left column
jp = n #jp right column
x = k #x starter number
while j < jp:
while j < jp:
a[i][j] = x
x += k
j +=1
it +=1
i=it+1
j=jp-1
while i< id:
a[i][j] = x
x += k
i +=1
jp -=1
j=jp-1
i=id-1
while j > jt:
a[i][j] = x
x += k
j -=1
id -=1
i=id-1
j=jt+1
while i>it:
a[i][j] = x
x += k
i -=1
jt +=1
i=it+1
j=jt+1
for x in a:
print(x)
sleep(0.1)
Here's an example:
Each number is suppose to appear one by one.
(I'm just putting this here so I can post this since I need to add more details)
Not quite trivial.
I found a solution using an empty character array and cursor-manipulation.
This should result in the desired output:
# replace your last "for x in a" loop by the following
def print_array(arr, block_size=4):
"""
prints a 2-D numpy array in a nicer format
"""
for a in arr:
for elem in a:
print(elem.rjust(block_size), end="")
print(end="\n")
# empty matrix which gets filled with rising numbers
matrix_to_be_filled = np.chararray(a.shape, itemsize=3, unicode=True)
for _ in range(a.size):
# find position of minimum
row, col = np.unravel_index(a.argmin(), a.shape)
# add minimum at correct position
matrix_to_be_filled[row, col] = f'{a.min():.0f}'
# write partially filled matrix
print_array(matrix_to_be_filled)
# delete old minimum in a-matrix
a[row, col] = a.max()+1
sleep(0.1)
# bring cursor back up except for last element
if _ < a.size-1:
print('\033[F'*(matrix_to_be_filled.shape[0]+1))
If you are using pycharm, you need to edit the run/debug configuration and active "emulate terminal in output console" to make the special "move up" character work

Navigating the robot by finding the shortest way

I have this task where I have to make my robot find the shortest way when I enter a destination point. I've created some functions to assign numbers (distances) for each square and counts its way back to my robot by deleting the other options. Then the robot should only follow the numbers.
My code works so far, however I think I should be able to reach the same outcome by using less for loops and with a more efficient writing. I believe if I see different ways of thinking in my earlier stages, I can have a broader perspective in the future. So, any ideas on how to reach my goal with a shorter code?
#Your Code Starts Here
"""
for x in range(0, map.width):
for y in range(0, map.height):
if map.blocked(x, y):
map.value[x, y] = -1
else:
map.value[x, y] = 0
"""
def fill_around(n,m,number):
for x in range (n-1,n+2):
for y in range (m-1,m+2):
if map.value[x,y] != 0:
pass
elif x==n+1 and y==m+1 or x==n-1 and y==m-1 or x==n-1 and y==m+1 or x==n+1 and y==m-1:
pass
elif map.blocked(x,y) == True:
map.value[x,y]= -1
elif x==n and y==m:
map.value[x,y]= number
else:
map.value[x,y]= number+1
def till_final(final_x,final_y):
final_x=9
final_y=1
fill_around(1,1,1)
for p in range(2,17):
for k in range(0, map.width):
for l in range(0, map.height):
if map.value[final_x,final_y] ==0 and map.value[k,l]==p:
fill_around(k,l,p)
def delete_duplicates(final_x,final_y):
for k in range(0, map.width):
for l in range(0, map.height):
if map.value[k,l] == map.value[final_x,final_y] and k != final_x and l != final_y:
map.value[k,l] = 0

Partial Digest Problem(PDP) in python only spits out "None"

Partial Digest Problem is one of the algorithms for getting the places of cut in DNA. Given all the possible lengths of cut, for example [2,2,3,3,4,5,6,7,8,10] I have to figure out a way to find the actual places of cut. In this example total length of the DNA is 10, and the places of actual cut are [0,3,6,8,10].
From the algorithm above, I'm trying to build the actual code in python, and with hand I'm not sure what I've done wrong.
The desired output for this code is
[0,3,6,8,10]
where I'm only getting
"None"
Can anyone please tell me what part in my code is wrong?
# function to remove multiple elements given as list
def delete(elements,A):
for el in elements:
A.remove(el)
return A
# y is given as integer, X as list
def delta(y,X):
n = len(X)
for i in range(n):
X[i] -= y
X[i] = abs(X[i])
return sorted(X)
# If former contains latter, return true. Else, return false
def contains(small, big):
for i in range(len(big)-len(small)+1):
for j in range(len(small)):
if big[i+j] != small[j]:
break
else:
return True
return False
def partialDigest(L):
global width
width = (max(L))
delete([width], L) # Needs to be in list to feed to 'delete' function
X = [0, width]
X = place(L,X)
return X
def place(L,X):
if len(L) == 0: # Baseline condition
return X
y = max(L)
if contains(delta(y,X),L): # If former is the subset of L
delete(delta(y,X), L) # Remove lengths from L
X += list(y) # assert that this y is one of the fixed points, X
X = sorted(X) # To maintain order
print(X)
place(L,X) # Recursive call of the function to redo the upper part
# If none of the if statements match the condition, continue
X.remove(y) # If the code reaches down here, it means the assumption that
# y is one of the points is wrong. Thus undo
L += delta(y,X) # undo L
L = sorted(L) # To maintain order
# Do the same thing except this time it's (width-y)
elif contains(delta(width-y,X),L):
delete(delta(width-y,X), L)
X += list(width - y)
X = sorted(X)
place(L,X)
X.remove(width-y)
L += delta(y,X)
L = sorted(L)
L = [2,2,3,3,4,5,6,7,8,10]
X = partialDigest(L)
print(X)

Making lights out

I could really use some help with understanding where I am going wrong with 2d list comprehension. I have spent hours and the finer points of why its not working out continues to elude me.
The following code is a very basic Lights out game that takes an input
runGenerations2d([0,1,1,0],[1,0,1,0],[1,0,1,0])
Sets up a game board N x N
with a click it needs to change the value of the clicked box.
I believe the problem is
setNewElement
is taking x,y data and the rest of my functions haven't a clue what to do with the values passed on
import time # provides time.sleep(0.5)
from csplot import choice
from random import * # provides choice( [0,1] ), etc.
import sys # larger recursive stack
sys.setrecursionlimit(100000) # 100,000 deep
def runGenerations2d(L , x = 0,y=0):
show(L)
print( L ) # display the list, L
time.sleep(.1) # pause a bit
newL = evolve2d( L ) # evolve L into newL
print(newL)
if min(L) == 1:
#I like read outs to be explained so I added an extra print command.
if x<=1: # Takes into account the possibility of a 1 click completition.
print ('BaseCase Reached!... it took %i click to complete' % (x))
print (x)
done()#removes the need to input done() into the shell
else:
print ('BaseCase Reached!... it took %i clicks to complete' % (x))
print (x)
done()#removes the need to input done() into the shell
return
x = x+1 # add 1 to x before every recusion
runGenerations2d( newL , x,y ) # recurse
def evolve2d( L ):
N = len(L) # N now holds the size of the list L
x,y = sqinput2() # Get 2D mouse input from the user
print(x,y) #confirm the location clicked
return [ setNewElement2d( L, i,x,y ) for i in range(N) ]
def setNewElement2d( L, i, x=0,y=0 ):
if i == (x,y): # if it's the user's chosen column,
if L[i]==1: # if the cell is already one
return L[i]-1 # make it 0
else: # else the cell must be 0
return L[i]+1 # so make it 1
The error after a click
[None, None, None, None]
[None, None, None, None]
The data does not seem 2d.
Try using sqinput instead.
setNewElement2d returns a single number but the calling code is expecting two numbers.
This line
return [ setNewElement2d( L, i,x,y ) for i in range(N) ]
Is setting i to 0, then 1, then 2, ... then N-1. These are single numbers.
You then compare the single numbers to two numbers on this line:
if i == (x,y):
You seem to be assuming i is an x,y pair but it isn't.
Here's how to create every x-y pair for a 3x3 grid:
# Makes (0,0),(0,1)...(2,2)
[(x,y) for x in range(3) for y in range(3)]
I think this code is closer to what you want, still might need changing:
def evolve2d( L ):
N = len(L)
x,y = sqinput2()
print(x,y)
return [setNewElement2d(L, xx, yy, x, y) for xx in range(N) for yy in range(N)]
def setNewElement2d( L, xx, yy, x=0,y=0 ):
if (xx,yy) == (x,y): # if it's the user's chosen row and column
# If it's already 1 return 0 else return 1
return 0 if L[xx][yy]==1 else 1

Categories