Python Connect 4 Horizontal win - python

So Basically I am, trying to code the horizontal win condition for a connect 4 Game In python I figured out the way to do this for 4 Connecting Chips In python would be
for x in range(cols - 3):
for y in range(rows):
if board[x][y] == color and board[x+1][y] == color and board[x+2][y] ==color and board[x+3]==color:
return True
But The Problem is I need something similar to this to work a winning connecting chips as determined by the user it could be four or what ever amount the user wants.
for x in range(col - 3):
for y in range(row):
for z in range (0, required_connected_chips):
if board_values[x + z][y] == color:
required _Connecting_chips is the winning connecting chips as determined by the user after writing this i am basically stuck on what to do next and would take any suggestions or feedback on how to solve my problem and i am sorry if i got my indentation wrong on some of the code.

you could add a boolean to save the output of board_values[x + z][y] == color:. If this keeps True until the end of your loop return True. Like:
b = True
for z in range (0, required_connected_chips):
b &= board_values[x + z][y] == color
if b:
return True
Edit: for not checking every Field u might check b in the loops after setting it so it would look like:
b = True
for z in range (0, required_connected_chips):
if not board_values[x + z][y] == color:
b = False
break
if b:
return True
Edit2: removed redundant "&" in second code example
Edit3: changed the second code example a bit further to a way it feels bether for me

Related

How do I check if the move is valid or not made by Knight and Bishop

Complete the following function to validate the move of a given chess piece and return True (boolean) if the move is valid or False(boolean) if the move is invalid. The chessboard is given below for your reference.
Function takes 3 arguments
piece can be a "Knight" or "Bishop"
currentpos(a string) is a combination of row and column it be anything between "a1" to "h8". currentpos represents the cell on the chessboard where the piece is currently located
nextpos(a string) is also a combination of row and column and can also be between from "a1" to "h8". nextpos represents the cell to which the piece is intended to be moved
I have a hard time understanding this question. Can anyone tell me the correct approach for this problem?
def valid_move_or_not(piece,currentpos,nextpos):
#Write your code here
return True
if __name__=='__main__':
#you can run your tests here
print(valid_move_or_not("Knight","a1","a2"))
Calculate the displacement in the X and Y axes. You'll find the pattern.
Valid Bishop move results in equal displacement in both axes.
Valid Knight move results in 1,2 or 2,1 blocks displacement in X, Y axes respectively.
def valid_move_or_not(piece, currentpos, nextpos):
coord = lambda x: (ord(x[0]) - ord('a'), int(x[1]))
xdiff = abs(coord(currentpos)[0] - coord(nextpos)[0])
ydiff = abs(coord(currentpos)[1] - coord(nextpos)[1])
if piece == "Bishop":
return xdiff == ydiff
elif piece == "Knight":
return xdiff == 2 and ydiff == 1 or xdiff == 1 and ydiff == 2
It asks you to code the move rule of chess pieces. You can google if you are not familiar with chess.
As a simple example, you can check the validity of a Rook move like below
def valid_move_or_not(piece,currentpos,nextpos):
if currentpos == nextpos:
return False
if piece == 'Rook':
return (currentpos[0] == nextpos[0]) or (currentpos[1] == nextpos[1])

How to make a function determining the winner of Tic-Tac-Toe more concise

I'm writing a Python script which is supposed to allow human and computer players to play Tic Tac Toe. To represent the board, I'm using a 3x3 Numpy array with 1 and 0 for the marks of the players (instead of "X" and "O"). I've written the following function to determine the winner:
import numpy as np
class Board():
def __init__(self, grid = np.ones((3,3))*np.nan):
self.grid = grid
def winner(self):
rows = [self.grid[i,:] for i in range(3)]
cols = [self.grid[:,j] for j in range(3)]
diag = [np.array([self.grid[i,i] for i in range(3)])]
cross_diag = [np.array([self.grid[2-i,i] for i in range(3)])]
lanes = np.concatenate((rows, cols, diag, cross_diag))
if any([np.array_equal(lane, np.ones(3)) for lane in lanes]):
return 1
elif any([np.array_equal(lane, np.zeros(3)) for lane in lanes]):
return 0
So for example, if I execute
board = Board()
board.grid = np.diag(np.ones(3))
print board.winner()
I get the result 1. What bothers me slightly is the repetition of the any statements. I would think there would be a more concise, DRY way of coding this. (I was thinking of a switch/case as in MATLAB but this doesn't exist in Python). Any suggestions?
Another option is to check the sum of lanes.
s = np.sum(lanes, axis=1)
if 3 in s:
return 1
elif 0 in s:
return 0
I have made a loop instead, and return only once, to conform with PEP8 and to be honest to my personal coding standards :)
enumerate in the correct order will yield 0,zeromatrix then 1,onematrix
rval = None
for i,m in enumerate([np.zeros(3),np.ones(3)]):
if any([np.array_equal(lane, m) for lane in lanes]):
rval = i; break
return rval
I found out one way, by using a Lambda function:
any_lane = lambda x: any([np.array_equal(lane, x) for lane in lanes])
if any_lane(np.ones(3)):
return 1
elif any_lane(np.zeros(3)):
return 0
This adds an extra line to the code but makes it more legible overall, I reckon.
This can be done in two lines, starting from the board (grid): simple sums along columns, rows and the two main diagonals gives you a value of 0 or 3 depending on who is winning (or some intermediate values only if nobody is winning). You can thus calculate something like:
# Score along each column, row and both main diagonals:
scores = (grid.sum(axis=0).tolist() + grid.sum(axis=1).tolist()
+[grid.trace(), np.flipud(grid).trace()])
# If there is no winner, None is declared the winner:
print "Winner:", 1 if 3 in scores else 0 if 0 in scores else None
where flipud() transforms the diagonal into the anti-diagonal (the diagonal at 90° from the main diagonal) by flipping the array horizontally, so that a simple trace() gives the total value along the anti-diagonal.

How can I access the integer held in a variable which is defined by a separate definition

Current section I'm working on requires me to take coloured pieces from the bar and place them onto a board.
I've had to define the board through makeBoard and the values are stored in "myBoard"
What I'm struggling with is that on my next section "enterPiece" I've got it so I successfully take the relevant coloured pieces from the bar, detract it from the number and then allocate the piece to the board..
what I'm aiming to do is.. 0 < aPoint <= n (where n is the size of the board where I've defined in makeBoard), but I don't know how to get python to get the n from the variable myBoard
def enterPiece(aBoard, aColour, aPoint):
c = aBoard
if 0 < aPoint:
for j in range(aPoint):
c.removePieceFromPoint(aColour, 0)
c.addPieceToPoint(aColour, aPoint)
return True
else:
return False
it looks like n is Board.size, so you should be able to rewrite as:
def enterPiece(aBoard, aColour, aPoint):
c = aBoard
if 0 < aPoint <= aBoard.size:
for j in range(aPoint):
c.removePieceFromPoint(aColour, 0)
c.addPieceToPoint(aColour, aPoint)
return True
else:
return False

Python: List index out of range, don't know why

I'm trying to iterate through a matrix and check for the number of cells touching the current cell that have a value of 1. I'm getting an out of bounds exception and I'm not sure why.
for x in range(0,ROWS):
for y in range(0,COLS):
#get neighbors
neighbors = []
if x!=0 & y!=COLS:
neighbors.append([x-1,y+1])
if y!=COLS:
neighbors.append([x,y+1])
if x!=ROWS & y!=COLS:
neighbors.append([x+1,y+1])
if x!=0:
neighbors.append([x-1,y])
if x!=ROWS:
neighbors.append([x+1,y])
if x!=0 & y!=0:
neighbors.append([x-1,y-1])
if y!=0:
neighbors.append([x,y-1])
if x!=ROWS & y!=0:
neighbors.append([x+1,y-1])
#determine # of living neighbors
alive = []
for i in neighbors:
if matrix[i[0]][i[1]] == 1:
alive.append(i)
I'm getting the error
IndexError: list index out of range
at this line if matrix[i[0]][i[1]] == 1:
Why is this out of range and how should I fix it?
The problem is that you are using &. This is a bit-wise AND, not a logical AND. In Python, you just use and. For example:
if x!=0 and y!=COLS:
neighbors.append([x-1,y+1])
However the real reason why using the bit-wise AND causes a problem is order of operations - it has a higher precedence!
>>> 1 != 2 & 3 != 3
True
>>> (1 != 2) & (3 != 3)
False
>>> 1 != (2 & 3) != 3
True
So even though your logic looks right, order of operations means that your code's actual behavior is drastically different than what you were expecting.
The other issue with your code is that you are checking if x and y are equal to ROWS and COLS, rather than if they are equal to ROWS-1 and COLS-1, which are the true boundary conditions.
EDIT: I THINK I FOUND IT
Upon further inspection of your code, I found that you're using if x!=0 & y!=0. This is bit-wise AND not logical AND, so it's not going to give you the result you want. Use and instead of & and see if your problem goes away.
I would refactor this slightly to make it easier to read.
for loc_x in range(ROWS):
for loc_y in range(COLS): # btw shouldn't ROWS/COLS be flipped?
# if your matrix isn't square this could be why
x_values = [loc_x]
if loc_x < ROWS: x_values.append(loc_x+1)
if loc_x > 0: x_values.append(loc_x-1)
y_values = [loc_y]
if loc_y < COLS: y_values.append(loc_y+1)
if loc_y > 0: y_values.append(loc_y-1)
neighbors = [(x,y) for x in x_values for y in y_values if (x,y) != (loc_x,loc_y)]
alive = [matrix[n[0]][n[1]] for n in neighbors if matrix[n[0]][n[1]]==1]
Try running this with your code and see if it doesn't solve the issue. If not, you may need to test further. For instance, wrap the alive definition in try/except tags that will give a better traceback.
try:
alive = ...
except IndexError:
print("Location: {},{}\nneighbors: {}\nROWS:{}\nCOLS:{}".format(x_loc,y_loc, neighbors,ROWS,COLS))
raise
As an aside, I've solved this problem before by creating objects that held the linked information and going top-to-bottom left-to-right and having each check the field to its right and below it. E.g.:
class Field(object):
def __init__(self,x,y,value):
self.x = x
self.y = y
self.value = value
self.neighbors = neighbors
class Matrix(list):
def __init__(self,size):
self.ROWS,self.COLS = map(int,size.lower().split("x"))
for y in range(ROWS):
self.append([Field(x,y,random.randint(0,1)) for x in range(COLS)])
self.plot()
def plot(self):
for row in self:
for col in row:
try:
self[row][col].neighbors.append(self[row+1][col])
self[row+1][col].neighbors.append(self[row][col])
except IndexError: pass
try:
self[row][col].neighbors.append(self[row][col+1])
self[row][col+1].neighbors.append(self[row][col])
except IndexError: pass
Of course this doesn't take care of diagonals. I'm pretty sure you can figure out how to manage those, though!!

Game Of Life : How to keep track of active cells

Now I have read the other stackoverflow Game of Life questions and also Googled voraciously.I know what to do for my Python implementation of the Game Of Life.I want to keep track of the active cells in the grid.The problem is I'm stuck at how should I code it.
Here's what I thought up but I was kinda at my wit's end beyond that:
Maintain a ActiveCell list consisting of cell co-ordinates tuples which are active
dead or alive.
When computing next generation , just iterate over the ActiveCell list,compute cell
state and check whether state changes or not.
If state changes , add all of the present cells neighbours to the list
If not , remove that cell from the list
Now the problem is : (" . "--> other cell)
B C D
. A .
. . .
If A satisfies 3) then it adds B,C,D
then if B also returns true for 3) ,which means it will add A,C again
(Duplication)
I considered using OrderedSet or something to take care of the order and avoid duplication.But still these I hit these issues.I just need a direction.
don't know if it will help you, but here's a quick sketch of Game of Life, with activecells dictionary:
from itertools import product
def show(board):
for row in board:
print " ".join(row)
def init(N):
board = []
for x in range(N):
board.append([])
for y in range(N):
board[x].append(".");
return board
def create_plane(board):
board[2][0] = "x"
board[2][1] = "x"
board[2][2] = "x"
board[1][2] = "x"
board[0][1] = "x"
def neighbors(i, j, N):
g1 = {x for x in product([1, 0, -1], repeat=2) if x != (0, 0)}
g2 = {(i + di, j + dj) for di, dj in g1}
return [(x, y) for x, y in g2 if x >= 0 and x < N and y >= 0 and y < N]
def live(board):
N = len(board)
acells = {}
for i in range(N):
for j in range(N):
if board[i][j] == "x":
for (x, y) in neighbors(i, j, N):
if (x, y) not in acells: acells[(x, y)] = board[x][y]
while True:
print "-" * 2 * N, len(acells), "cells to check"
show(board)
raw_input("Press any key...")
for c in acells.keys():
a = len([x for x in neighbors(c[0], c[1], N) if board[x[0]][x[1]] == "x"])
cur = board[c[0]][c[1]]
if a == 0:
del acells[c] # if no live cells around, remove from active
elif cur == "x" and a not in (2, 3):
acells[c] = "." # if alive and not 2 or 3 neighbors - dead
elif cur == "." and a == 3:
acells[c] = "x" # if dead and 3 neighbors - alive
for x in neighbors(c[0], c[1], N): # add all neighbors of new born
if x not in acells: acells[x] = board[x[0]][x[1]]
for c in acells:
board[c[0]][c[1]] = acells[c]
N = 7
board = init(N)
create_plane(board)
live(board)
You have two lists, I'll name them currentState, and newChanges. Here will be the workflow:
Iterate over currentState, figuring out which are newly born cells, and which ones are going to die. Do NOT add these changes to your currentState. If there is a cell to be born or a death, add it to the newChanges list. When you are finished with this step, currentState should look exactly the same as it did at the beginning.
Once you have finished all calculations in step 1 for every cell, then iterate over newChanges. For each pair in newChanges, change it in currentState from dead to alive or vice versa.
Example:
currentState has {0,0} {0,1} {0,2}. (Three dots in a line)
newChanges is calculated to be {0,0} {-1,1} {1,1} {0,2} (The two end dots die, and the spot above and below the middle are born)
currentState recieves the changes, and becomes {-1,1} {0,1} {1 ,1}, and newChanges is cleared.
Did you consider using an ordered dictionary and just set the values to None?
You didn't state that you have a restriction to implement the game in a specific way. So, the main question is: how big a grid do you want to be able to handle?
For example, if you are starting with a small fixed-size grid, the simplest representation is just a [[bool]] or [[int]] containing whether each cell is alive or dead. So, each round, you can make a new grid from the old one, e.g. assuming that all cells outside the grid are dead. Example:
[
[False, True, False],
[True, False, True],
[False, True, False],
]
If you want a very large dynamic-sized grid, there's the HashLife algorithm, which is much faster, but more complicated.
I implemented Game of Life in Python for fun and what I did was having board dict, with tuples of coordinates. Value is a state of cell. You can look at the code here https://raw.github.com/tdi/pycello/master/pycello.py. I know this is not very fast implementation and the project is abandoned due to lack of time.
board = {}
board[(x,y)] = value

Categories

Resources