How to create a matrix with moving elements? - python

I am trying to create a code for an 8x8 matrix that is full of zeros except[1,1] and [8,8]. These values would be equal to 1. I then want to make the 1's at each corner be able to move up, down, left, right, as long as it is within the matrix. I would like to be able to find out how many moves until the 1's cross each other.
I understand I need to make 2 arrays but really unsure how to code this.

You can use a for loop to create the matrix like this:
matrix = []
for x in range(8):
matrix.append([])
for y in range(8):
matrix[x].append(0)
Then you can change matrix[1][1], and matrix[8][8] to 1's.
However, I'm pretty sure you meant matrix[0][0] and matrix[7][7] because list indexing starts at [0].
matrix[0][0] = 1
matrix[7][7] = 1
To move the 1's across the matrix, you can create a function called move() and then remember the positions of the 1's in variables
posX = [0, 7]
posY = [0, 7]
#argument dirn, 0 = right, 1 = left, 2 = up, 3 = down
#argument one, gives which one you want to move
def move(dirn, one):
if dirn == 0 and posX[one] < 7:
matrix[posX[one]][posY[one]] = 0
matrix[posX[one] + 1][posY[one]] = 1
posX[one] = posX[one] + 1
if dirn == 1 and posX[one] > 0:
matrix[posX[one]][posY[one]] = 0
matrix[posX[one] - 1][posY[one]] = 1
posX[one] = posX[one] - 1
if dirn == 2 and posY[one] < 7:
matrix[posX[one]][posY[one]] = 0
matrix[posX[one]][posY[one] + 1] = 1
posY[one] = posY[one] + 1
if dirn == 3 and posY[one] > 0:
matrix[posX[one]][posY[one]] = 0
matrix[posX[one]][posY[one] - 1] = 1
posY[one] = posY[one] - 1
You can find out how many moves until the 1's cross each other, by adding 1 to a variable every time you make a move. Then check if the ones are crossing each other.
moves = 0
while not [posX[0], posY[0]] == [posX[1], posY[1]]:
#make a move
moves += 1
Total moves made will be the moves variable after the process has ended. Print the value of the moves variable after the while loop.
print(moves)

Related

index 20 is out of bounds for axis 0 with size 20

I am trying to create a function that has an array of zeros with a 1 at the center. Using randrange, the function decides where to add a count in the array with respect to the center. The new site will then be the new reference rather than the center. This should happen for m iterations. Once the array has a 1 in the first site, then the function should return the m value in which this occurred.
def random_walk_mod(n,m):
array = np.zeros(n) #create array of zeros of length n
array[n//2] = 1
start_pos = n//2
for i in range(m):
direction = randrange(-1,2,2) #get direction of left or right
pos = start_pos + direction #Change position from center
array[pos] = array[pos]+1
start_pos = pos
if array[0] == 1:
return i
However when calling the function more than once with
for i in range(20):
m = random_walk_mod(20,1000):
print(m)
I get this error
index 20 is out of bounds for axis 0 with size 20
The issue come from this line.
pos = start_pos + direction
Your direction can be 1 or - 1, but if it's 10 time 1, as your exemple start with 20, you will get 20 // 2 + 10 = 20. As you have create an array with 20 value, index 20 does not exist.
Now you can catch it with a try/except block or you can add another condition to check if 1 is at the end of your array.
You need to place a stopper for the right side of the array to prevent to going out of range. This should work:
def random_walk_mod(n,m):
array = np.zeros(n) #create array of zeros of length n
array[n//2] = 1
start_pos = n//2
for i in range(m):
direction = random.randrange(-1,2,2) #get direction of left or right
pos = start_pos + direction #Change position from center
array[pos] = array[pos]+1
start_pos = pos
if array[0] == 1:
return i
if array[n-1] == 1: #This code will prevent your index for going to far on the right
return i

Function to find winning line with NxN board and M pieces in a row in Python 3

I am trying to create a function that finds if a move is winning on an NxN board where the winning condition is M pieces in a row in Python 3.
I am pretty new to programming and in my specific case I am creating a Gomoku game (15x15 board with 5 pieces in a row to win). To get it working I created 6 for loops to check vertical, horizontal and 4 diagonals. See the code below for examples on the 2 options for left to right digonals. This takes way too long though when I need to loop through it many times (8) for computer to find if I can win or if it has a winning move.
end_row = 15
for j in range(11):
end_row -= 1
counter = 0
for i in range(end_row):
if board[i+j][i] == board[i+1+j][i+1] and board[i+j][i] != ' ':
counter += 1
if counter == 4:
winning_line = [(i+j-3, i-3), (i+j-2, i-2), (i+j-1, i-1), (i+j, i), (i+1+j, i+1)]
winner = True
break
else:
counter = 0
# Top left to bottom right, lower side
end_row = 15
for j in range(11):
end_row -= 1
counter = 0
for i in range(end_row):
if board[i][i+j] == board[i+1][i+1+j] and board[i][i+j] != ' ':
counter += 1
if counter == 4:
winning_line = [(i-3, i+j-3), (i-2, i+j-2), (i-1, i+j-1), (i, i+j), (i+1, i+1+j)]
winner = True
break
else:
counter = 0
# What I want to do instead, where x and y are coordinates of last move:
# Horizontal
counter = 0
for i = x - (n - 1) to x + (n - 1):
if board[i][y] == board[x][y] :
counter++
else :
counter = 0
if counter == n:
return true
The problem with the lower part of the code is that if I place a piece on e.g. position (0, 0) the program will complain when trying to reach board[-4][0] in the first looping. I will have to place lots of if statements when I get close to the edge, which is not an elegant solution.
I thought of making a 3*15 x 3*15 board instead, where the actual board is the inner 15x15 part and the rest just contains placeholders:
15x15 || 15x15 || 15x15
15x15 || board || 15x15
15x15 || 15x15 || 15x15
This to avoid getting outside of my list of lists when looping through. Not an elegant solution either, but takes less space in the code.
Any suggestions on how to solve this problem? Thank you in advance from a beginner programmer!
As #MePsyDuck mentioned in comments, you can use min and max functions to limit the range to only reference valid squares in the board matrix.
Furthermore, you could make a generic function that does the count-job on any given list of values. Then you can call that generic function four times: once for every direction (horizontal, vertical, diagonal \ and diagonal /)
Here is how that could work:
def is_win(board, n, x, y):
end_row = len(board)
color = board[x][y]
def check(values):
counter = 0
for value in values:
if value == color:
counter += 1
else:
counter = 0
if counter == n:
return True
return False
return (check([board[i][y] for i in range(max(0, x - n + 1), min(end_row, x + n))])
or check([board[x][i] for i in range(max(0, y - n + 1), min(end_row, y + n))])
or check([board[x+i][y+i] for i in range(max(-x, -y, 1 - n), min(end_row - x, end_row - y, n))])
or check([board[x+i][y-i] for i in range(max(-x, y - end_row + 1, 1 - n), min(end_row - x, y + 1, n))]))
Instead of looping from 0 to 14, just loop from 0 to (board_size - winning_length).
Here's an example for a 1-dimensional board:
BOARD_SIZE = 15
WINNING_LENGTH = 5
for x in range(BOARD_SIZE - WINNING_LENGTH):
players_here = set()
for pos in range(x, x + WINNING_LENGTH):
players_here.add(board[pos])
if len(players_here) == 1:
# Exactly 1 player occupies every position in this line, so they win

Python: Directional Navigation in 2d Array

TLDR: I want to navigate all directions in a 2D array starting at the center
I am trying to do a particular navigation in a 2D Python array. Say I have this 2D array (A1):
I want to navigate through this array and apply the summation of the index for A1 * index of A2 where A2 is another 2D array (A2):
When applying the summation, I want the current index, to start with the center of the second 2D array. So at A1[0][0] (1) I want to use the center of A2 (A21, or 0). I then want to move through each item in the second array and continue this process:
1(0) + 2(1) + 5(2) + 6(1)
This will take care of all the items from A2[center x][center y]. I then want to double back, and add all the values that are below the center. Here is a quick image illustrating what I want to do, one showing a case where we are out of bounds, and on, in bounds:
What I am trying to do is write a function that will navigate, from the center of a 2D array, out in each direction of that 2D array. Here is the code I have for it:
for row in range(A1.length):
for column in range(A1[0].length):
cRow = 0
pSum = 0
kRow = midRow - 1
while kRow < A2.length and row + kRow < A1.length:
kColumn = midColumn - 1
cColumn = 0
while kColumn < A2[0].length and column + kColumn < A1[0].length:
pSum += float(A1[row + cRow][column + cColumn] * A2[kRow][kColumn])
kColumn += 1
cColumn += 1
kRow += 1
cRow += 1
nKRow = midRow - 1
cRow = 0
#Get rows past
while nKRow >= 0 and row - nKRow >= 0:
nKColumn = midColumn - 1
cColumn = 0
while nKColumn >= 0 and column - nKColumn >= 0:
# Account for row 0
if row == 1 and cColumn == 0:
pSum += float(A1[0][column - cColumn] * A2[nKRow][nKColumn])
else:
pSum += float(A1[row - cRow][column - cColumn] * A2[nKRow][nKColumn])
nKColumn -= 1
cColumn += 1
nKRow -= 1
cRow += 1
value = float(pSum / average)
A3[row][column] = value
This works in most cases, but does not work correctly in edge cases. The problem is that I am having issues setting values when row = 0 or column = 0.
Is there a better approach to navigate every direction in a 2d array starting at the center?
It looks like you are trying to do kernel convolution, yes?
Where are midRow, midColumn, and average defined in your example?
Why do you have to start in the center of A2? Summation and multiplication are both commutative operations, so the order shouldn't matter. It would be much simpler to start in the top left corner of A2. Something like (I haven't tested this):
kernelSize = 3
kernelOffset = int(kernelSize / 2) # Assumes only odd-sized kernels
for x in xrange(len(A1)):
for y in xrange(len(A1[0])):
total = 0
for kx in xrange(kernelSize):
for ky in xrange(kernelSize):
offsetX = -kernelOffset + kx # Should give something in the range [-1, 1]
offsetY = -kernelOffset + ky
currentX = x + offsetX
currentY = y + offsetY
if currentX < 0 or currentX >= len(A1) or currentY < 0 or currentY >= len(A1[0]): # do nothing if "out of bounds"
continue
total += A1[currentX][currentY] * A2[kx][ky]
A3[x][y] = total

Conway's Game of Life with Python

I took a liking to Conway's Game of Life and began to try and write it in python. At this moment I have yet to write any code for the borders of the program so I am just asking for help with what I have right now. I seem to have trouble when initialization a "blinker" formation. Instead of oscillating like it should, it seems to turn itself into a cube.
#File: gameoflife.py
#Description: This is a basic "life" simulation that follows three distinct rules:
#1.Any live cell with fewer than two live neighbours dies
#2.Any live cell with two or three live neighbours lives
#3.Any live cell with more than three live neighbours dies
#4.Any dead cell with exactly three live neighbours becomes a live cell
#A neighbor is deemed as any cell directly horizantal/vertical/diagonal
#meaning there are 9 neighbors to a cell at any time
from graphics import *
import random
from time import sleep
def initial(D,M,win):
#Creates the white board background
for i in range (11):
m = [] # rectangle list
for j in range (11):
rec = Rectangle(Point(6 + 4 * i, 6 + 4 * j), Point(10 + 4 * i, 10 + 4 * j))
D[i][j] = 0
rec.setFill("white")
rec.draw(win)
m.append(rec)
M.append(m)
def check(x,y,D):
#Checks all 9 adjacent neihbors to see if "alive" and checks this number
#means the cell should stay alive(1), die(0), or if already dead come
#back alive(2)
counter = 0
if D[x+1][y] == 1:
counter += 1
if D[x-1][y] == 1:
counter += 1
if D[x][y+1] == 1:
counter += 1
if D[x][y-1] == 1:
counter +=1
if D[x+1][y+1] == 1:
counter+=1
if D[x+1][y-1] == 1:
counter+= 1
if D[x-1][y-1] == 1:
counter += 1
if D[x-1][y+1] == 1:
counter +=1
if counter<2 or counter>3:
return 0
if counter == 2:
return 1
if counter == 3:
return 2
def main():
win = GraphWin("Game of Life", 700, 600)
win. setCoords(0, 0, 70, 60)
#Initialize two dimesion arrays.
#D records color of grids, M records rectangles
D = []
M = []
C = []
#initialize the grids to create all "white"
for i in range(11):
d = []
c = []
for j in range(11):
d.append(0)
c.append(0)
D.append(d)
C.append(c)
initial(D,M,win)
#Initialzes three "alive" units
D[5][5],D[4][5] ,D[6][5]= 1,1,1
C[5][5],C[4][5] ,C[6][5]= 1,1,1
M[5][5].setFill("Black")
M[4][5].setFill("Black")
M[6][5].setFill("Black")
#Contiually checking
while True:
#Purposfully not checking the "Borders" of the array
for i in range (len(D)-1):
for j in range(len(D[i])-1):
#If the cell is alive
if D[i][j] == 1:
#If the cell should die
if check(i,j,D) == 0:
sleep(1)
#Sets a temporary list to white
C[i][j] = 0
#Fills the cell white
M[i][j].setFill("White")
#if the cell is dead
if D[i][j] == 0:
#If the cell should be revived
if check(i,j,D) == 2:
sleep(1)
#Sets a temporary list to black
C[i][j] = 1
#Fills the cell black
M[i][j].setFill("Black")
#Sets the main list = to the temporary list
D = C
main()
You will need to swap D and C, and not just assign C to D. As it stands now, D and C will be referring to the same list after the first iteration.
Here is a simple algorithm to do Conway's Game of Life in python using a numpy array of arbitrary 2D size:
import numpy
# this function does all the work
def play_life(a):
xmax, ymax = a.shape
b = a.copy() # copy grid & Rule 2
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 # Rule 1 and 3
elif n == 3:
b[x, y] = 1 # Rule 4
return(b)
# replace (5, 5) with the desired dimensions
life = numpy.zeros((5, 5), dtype=numpy.byte)
# place starting conditions here
life[2, 1:4] = 1 # a simple "spinner"
# now let's play
print(life)
for i in range(3):
life = play_life(life)
print(life)
This is not very efficient, but will certainly get the job done. Replace print(life) with whatever graphical calls you prefer.

List.append() changing all elements to the appended item [duplicate]

This question already has answers here:
Why does foo.append(bar) affect all elements in a list of lists?
(3 answers)
Closed 4 years ago.
I seem to have a problem with my maze generating program made in Python. I'm trying to randomly create a path that branches out at select points, with the points getting stored as it goes along. When the maze gets to a dead end, it will sort back through the visited points by testing the top value than popping that and going to the next one, until it gets to a spot where it isn't a dead end. However, when I try to append items to the list I'm using to save the spaces I've been to, something strange happens, I've never seen it before actually. Here's the code, and the best way to see it is to run it a through times until it goes all the way through. I haven't really found a way to counter the dead end problem, so if anyone could help me with that also, that would be great.
import random
width = 8
def check(x,y):
"""Figures out the directions that Gen can move while"""
if x-1 == -1:
maze[x][y][3] = 0
if x+1 == 8:
maze[x][y][1] = 0
if y+1 == 8:
maze[x][y][2] = 0
if y-1 == -1:
maze[x][y][0] = 0
if x + 1 in range(0,8) and visited[x+1][y] == False:
maze[x][y][1] = 2
if x - 1 in range(0,8) and visited[x-1][y] == False:
maze[x][y][3] = 2
if y + 1 in range(0,8) and visited[x][y+1] == False:
maze[x][y][2] = 2
if y - 1 in range(0,8) and visited[x][y-1] == False:
maze[x][y][0] = 2
def Gen(x,y):
visited[x][y] = True
past.append(current)
dirs = []
check(x,y)
print current
if maze[x][y][0] == 2:
dirs.append(0)
if maze[x][y][1] == 2:
dirs.append(1)
if maze[x][y][2] == 2:
dirs.append(2)
if maze[x][y][3] == 2:
dirs.append(3)
pos = random.choice(dirs)
print dirs
maze[x][y][pos] = 1
if pos == 0:
current[1] -= 1
if pos == 1:
current[0] += 1
if pos == 2:
current[1] += 1
if pos == 3:
current[0] -= 1
if maze[x][y][0] == 4:
maze[x][y][0] = 1
if maze[x][y][1] == 4:
maze[x][y][1] = 1
if maze[x][y][2] == 4:
maze[x][y][2] = 1
if maze[x][y][3] == 4:
maze[x][y][3] = 1
print maze[x][y]
print past, '\n'
#Build the initial values for the maze to be replaced later
maze = []
current = [0,0]
visited = []
past = []
#Generate empty 2d list with a value for each of the xy coordinates
for i in range(0,width):
maze.append([])
for q in range(0, width):
maze[i].append([])
for n in range(0, 4):
maze[i][q].append(4)
#Makes a list of falses for all the non visited places
for x in range(0, width):
visited.append([])
for y in range(0, width):
visited[x].append(False)
#Generates the walls
#for q in range(0, width):
# for i in range(0, width):
# check(q, i)
current = [0,0]
while current != [7,7]:
Gen(current[0], current[1])
print maze
As you can see, it starts at 0,0 and then figures out the possible paths to take. It randomly selects from those and sets the value for that side of the room in 0,0 to 1, which means a passage. 2 means wall and 0 means out of bounds. 4 is just a placeholder as all values should be filled by the time the maze is completely generated.
If anyone could help me, that would be great and very appreciated. Thanks in advance.
I believe the current list is simply copied multiple times into past. So you have multiple copies of the same list.
To fix: in the line past.append(current) (two lines below def Gen(x,y):), change it to past.append(current[:]).
The notation list[:] creates a copy of the list. Technically, you are creating a slice of the whole list.
By the way, a better solution would be to not use a global current variable :)
Yeah this is correct while List Comprehension in Python you need to append by strip other wise it will replace multiple times

Categories

Resources