Creating Lights On Game - python

I'm working on writing code for a game called Lights On where the idea of the game is to produce a board of randomly lit squares and to win all squares must be lit (1 is on 0 is off). Clicking on a square inverts that square and any squares neighboring it above, below, left, or right. However, I am having trouble inverting the board correctly using my code bellow
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)
x,y = sqinput2()
return [[ setNewElement2d( L, i, j,x,y ) for i in range(N)]for j in range(N) ]
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[i][j]
elif x==i and (j == y-1 or j == y+1):
return 1-L[i][j]
else:
return L[i][j]
I believe the issue is with my setNewElement2d function, but I cannot seem to figure it out.

Short answer: You've swapped i and j in evolve2d().
Long answer: When evolve2d() creates the new matrix, i needs to be in the outer loop, not the inner loop. Else, swap i and j. For example, if I change the call to
return [[ setNewElement( L, j, i, x, y ) for i in range(N) ] for j in range(N) ]
then I get the correct answer for your example.
This has to do with the organization of a two-dimensional array. In Python, L[i][j] looks in the ith row (vertical count down) and the jth column (horizontal count right). But you want i to compare to the x value, which in your mind is horizontal. So the point you're testing against has its coordinates swapped from the points you think you're testing against.
Last edit, I swear: Basically, the program did exactly what it was supposed to do. But when you looked at it, you imagined x and y to have the traditional meanings (horizontal and vertical, respectively) when in the array they have the opposite meanings: L[x][y] looks down x rows and right y columns.

Related

Rectangle function that takes in two points and makes a rectangle in a global matrix not working

I have a matrix of 50 by 50 that represents a grid of 25 by 25.
I want all the positives on the grid to get +25 and the negatives stay there absolute value.
But what my problem actually is I am creating a function that will create a rectangle based on the given values.
Code (Python 3.10.5):
def createRect(x,y,x1,y1,item):
global matrix
for i in range(x1,x,-1):
matrix[i][y1]=item
for i in range(y1,y-1,-1):
matrix[x][i] = item
for j in range(1,6):
for i in range(y1-1,y-1,-1):
matrix[x+j][i] = item
matrix = [['. ']*50 for _ in range(50)]
x,y,x1,y1 = 25+2,25+5,25+7,25+9
x2,y2,x3,y3 = 25+6,25+2,25+9,25+10
createRect(x,y,x1,y1,'# ')
createRect(x2,y2,x3,y3,'- ')
for i in range(50):
for j in range(50):
print(matrix[i][j], end = "")
print()
I tried using the function on another set of points but it only works for the first one seeing as its the only rectangle.
I am a bit confused about your code there, as why you fill the matrix backwards (for i in range(x1,x,-1)) and why would you include a hardcoded 6 there (for j in range(1,6)) so I might as well not have understood what the problem is. But wouldn't the following create the rectangles as per the given points? :
def createRect(x, y, x1, y1, item):
global matrix
for i in range(x, x1+1):
for j in range(y, y1+1):
matrix[i][j] = item

Python Edit distance algorithm with dynamic programming and 2D Array - Output is not optimal

I have encountered the edit distance (Levenshtein distance) problem. I have looked at other similar stackoverflow questions, and is certain that my question is distinct from them - either from the language used or the approach.
I have used a 2D array that compares the two strings, and dynamic programming to store previous values. If i and j in the string indices match, it would output 0, as we don't need to do anything; else, the output is 1. It is as shown in the picture below, the orange arrow represents a match.
(Code below is edited after suggestions from answers)
def edit_distance(source, target):
n = len(target)+1
m = len(source)+1
# let D denote the 2-dimensional array, m is the column, n is row
D = [ [0]*m for _ in range(n)]
# the loop inside is the target string, we operate this
# while the loop outside is the source string
for j in range(0, m):
for i in range(0, n):
if target[i-1] == source[j-1]:
# match, insertion and deletion, find the path with least move
D[i][j] = min(D[i-1][j-1], D[i-1][j]+1, D[i][j-1]+1)
else:
# mismatch, insertion and deletion, find the path with least move
D[i][j] = min(D[i-1][j-1]+1, D[i-1][j]+1, D[i][j-1]+1)
return D[n-1][m-1]
print(edit_distance("distance", "editing"))
However, the final output was 8 in my code, while the optimal editing distance between the strings "editing" and "distance" should be 5, and I am very confused. Could you please help with it from the approach of dynamic programming?
You have 2 mistakes.
First is intialization. You fill everything with 0s, but then when you want to fill in D[1][m] you look in the cell above (where it should be m) and you find a 0. Make sure the borders are correctly filled in.
Second your iterations are off. range(1, n) over 'editing' will give you 'diting'. To fix it N and M by 1 (n=len(target) + 1) and in your comparison use target[i-1] == source[j-1].
Ah, looks like I have found a solution, that I'll have to answer my own question now. (I'm still confused with some parts, and am only answering this question to briefly introduce the new implementation, as to save the time of other kind helpers)
So firstly, I have missed a condition in the original code, that is, what if one of the two string inputs are empty? Then we'll have to insert everything from the other string. Henceforth, the optimal editing distance is just the length of this other string.
if i == 0:
D[i][j] = j
elif j == 0:
D[i][j] = i
Also, regarding the original for-loop of the code, I learnt my mistakes from GeeksforGeeks. If my understanding is correct, they are saying that if two indices (i and j) are consistent, all we need to do is to move diagonally upward on the graph (i-1 and j-1) without adding any counts.
Else if the indices do not match, we move either to the direction of i-1, j-1 or diagonally up dependently. I was right on this, apart from the fact the count is added after the move, whereas I have added them during the move.
I am still a bit unsure with how it worked, however I'll compare the two algorithms below, would be appreciated if someone could explain it further in the comments.
My original for-loop (present in the question)
for j in range(0, m):
for i in range(0, n):
if target[i-1] == source[j-1]:
D[i][j] = min(D[i-1][j-1], D[i-1][j]+1, D[i][j-1]+1)
else:
D[i][j] = min(D[i-1][j-1]+1, D[i-1][j]+1, D[i][j-1]+1)
And below is the new for-loop, whose output is correct after testing:
if target[i-1] == source[j-1]:
D[i][j] = D[i-1][j-1]
else:
D[i][j] = 1 + min(D[i][j-1], D[i-1][j], D[i-1][j-1])
Would be appreciated if someone could further explain how did this work, as I still only have a superfacial understanding of the new code
Final code:
def edit_distance(target, source):
m = len(target)+1
n = len(source)+1
D = [[0 for x in range(n)] for x in range(m)]
for i in range(m):
for j in range(n):
if i == 0:
D[i][j] = j
elif j == 0:
D[i][j] = i
elif target[i-1] == source[j-1]:
D[i][j] = D[i-1][j-1]
else:
D[i][j] = 1 + min(D[i][j-1], D[i-1][j], D[i-1][j-1])
return D[m-1][n-1]
print(edit_distance("distance", "editing"))
# output = 5, which is correct

Most constraining variable and least constraining value for N-Queens - Python

I was trying to solve the N-Queens(Only 1 solution) problem and I succeeded but my program could only calculate up to N = 47 in a good amount of time so I tried to implement least constraining value and most constraining variable and even though it got faster, it was still slow. What can I do to be able to calculate up to N = 1000?
def solve(n, x, board, mid_rows, sd_squares):
# If we are on the last row, it means we have put all the queens:
if x >= n:
print_board(board)
sys.exit(0)
for i in sd_squares:
# If we can put a queen on the current square, do it
if isOk(board, mid_rows[x], i, n):
board[mid_rows[x]][i] = 1
# Do the same thing for the next row
solve(n, x + 1, board, mid_rows, sd_squares)
# If we are here, it means we put the queen in the wrong square so we have to remove that queen
board[mid_rows[x]][i] = 0
I can't post the whole code because it's too long but please note that isOk(board, x, y, n) is a function that tells if we put a queen on the x row and y column it threatens other queens or not.
mid_rows is an array that includes the most middle rows to the side rows so like let's say n = 5, then it's [2,3,1,4,0] or when n = 6 it's [3,2,4,1,5,0].
sd_squares is a list that contains the side squares to middle squares. Like when n = 5 it's [0,4,1,3,2] or when n = 6 it's [0,5,1,4,2,3].

(Python) Checking the 3x3 in a Sudoku, are there better ways to do this?

My partner in a summative for HS gave me this algorithm, I was hoping somebody could tell me if there is a more eloquent way of coding this..
CB is current board position(global), its a list of lists.
for a in xrange(0, 3):
for b in xrange(0, 3):
for j in xrange(1, 4):
for k in xrange(1, 4):
boxsum += CB[3a + j][3b + k]
if not(boxsum == 45):
return False
boxsum = 0
First, the following code is not indented correctly:
if not(boxsum == 45):
return False
boxsum = 0
(with the current indentation it will always fail on the first time this code is executed)
Second, in the following line:
boxsum += CB[3a + j][3b + k]
you probably meant to do:
boxsum += CB[3*a + j][3*b + k]
And last, in order to check a 3x3 part of sudoku game it is not enough to check the sum - you should also check that every number between 1-9 is present (or in other words, that all the numbers are in the range 1-9 and there is no number that appears more than once).
There are dozens of "cleaner" ways to do so.
First of all, why not use numpy for matrices, where you are obviously working with a matrix? I am assuming your numeration (which is a bit odd, why you start numerating from "1"?)
import numpy as np
CB = np.array(CB)
def constraint3x3check(CB):
return np.all(np.sum( CB[3*a+1:3*a+3, 3*b+1:3*b+3)==45 for a in range(3) for b in range(3))
Given the sum of the box equals 45, that doesn't mean there are all 1-9 numbers present.
You could for example add your numbers to set and check if the length of the set is always 9.
Since the sum 45 does not mean the answer is correct, necessarily, a different way is needed. Personally, I would join the rows into a single list and compare them to the list (1,2,...9), e.g.
#assuming this is your format...
box = [[4,2,3],[1,5,9],[8,7,6]]
def valid_box(box):
check_list = []
for row in box:
check_list += row
return list(range(1,10)) == sorted(check_list)
Although the code creating the list could also be done with list comprehension (I have no idea which one is more efficient, processor-wise)
def valid_box2(box):
return list(range(1,10)) == sorted( [item for row in box for item in row ] )
Merge list code taken from Making a flat list out of list of lists in Python

How to wrap around to the start/end of a list?

I have a 2d array with a different species in each one. I pick a random element on the array and I want to count up how many of each species are in the eight squares immediately adjacent to that element.
But I want the array to wrap at the edges, so if I pick an element on the top row, the bottom row will be counted as "adjacent". How can I do this while iterating through j in range (x-1,x+1) and the same for j and y?
Also, is there a more elegant way of omitting the element I originally picked while looking through the adjacent squares than the if (j!=x or k!=y line?
numspec = [0] * len(allspec)
for i in range (0,len(allspec)):
#count up how many of species i there is in the immediate area
for j in range(x-1,x+1):
for k in range(y-1,y+1):
if (j!=x or k!=y):
numspec[hab[i][j]] = numspec[hab[i][j]]+1
You can wrap using j%8 that gives you a number from 0 to 7.
As for wrapping, I would recomend using relative indexing from -1 to +1 and then computing real index using modulo operator (%).
As for making sure you don't count the original element (x, y), you are doing just fine (I would probably use reversed contidion and continue, but it doesn't matter).
I don't quite understand your usage of i, j, k indexes, so I'll just assume that i is index of the species, j, k are indexes into the 2d map called hab which I changed to x_rel, y_rel and x_idx and y_idx to make it more readable. If I'm mistaken, change the code or let me know.
I also took the liberty of doing some minor fixes:
introduced N constant representing number of species
changed range to xrange (xrange is faster, uses less memory, etc)
no need to specify 0 in range (or xrange)
instead of X = X + 1 for increasing value, I used += increment operator like this: X += 1
Here is resulting code:
N = len(allspec)
numspec = [0] * N
for i in xrange(N):
for x_rel in xrange(-1, +1):
for y_rel in xrange(-1, +1):
x_idx = (x + xrel) % N
y_idx = (y + yrel) % N
if x_idx != x or y_idx != y:
numspec[hab[x_idx][y_idx]] += 1
You could construct a list of the adjacent elements and go from there. For example if your 2d list is called my_array and you wanted to examine the blocks immediately surrounding my_array[x][y] then you can do something like this:
xmax = len(my_array)
ymax = len(my_array[0]) #assuming it's a square...
x_vals = [i%xmax for i in [x-1,x,x+1]]
y_vals = [blah]
surrounding_blocks = [
my_array[x_vals[0]][y_vals[0]],
my_array[x_vals[0]][y_vals[1]],
my_array[x_vals[0]][y_vals[2]],
my_array[x_vals[2]][y_vals[0]],
my_array[x_vals[2]][y_vals[1]],
my_array[x_vals[2]][y_vals[2]],
my_array[x_vals[1]][y_vals[0]],
my_array[x_vals[1]][y_vals[2]],
]

Categories

Resources