I've made a word searching game.It will print out a grid containing some words.
The code goes like this:
import random
DirectionList = []
# Create a grid filled with "." representing a blank
def createGrid():
grid=[]
for row in range(15):
grid.append([])
for column in range(50):
grid[row].append(".")
return grid
# Print the grid to the screen
def printGrid(grid):
for row in range(len(grid)):
for column in range(len(grid[row])):
print(grid[row][column],end="")
print()
# Try to place the word. Return True if successful
# False if it failed and we need to try again.
def tryToPlaceWord(grid,word):
# Figure out the direction of the work.
# Change the 8 to a 7 if you don't want backwards
# words.
status_check = []
direction=random.randrange(0,8)
DirectionList.append(direction)
if( direction == 0 ):
x_change=-1
y_change=-1
if( direction == 1 ):
x_change=0
y_change=1
if( direction == 2 ):
x_change=1
y_change=-1
if( direction == 3 ):
x_change=1
y_change=0
if( direction == 4 ):
x_change=1
y_change=1
if( direction == 5 ):
x_change=0
y_change=1
if( direction == 6 ):
x_change=-1
y_change=1
if( direction == 7 ):
x_change=-1
y_change=0
# Find the length and height of the grid
height=len(grid)
width=len(grid[0])
# Create a random start point
column=random.randrange(width)
row=random.randrange(height)
# Check to make sure the word won't run off the edge of the grid.
# If it does, return False. We failed.
if( x_change < 0 and column < len(word) ):
status_check.append(False)
status_check.append("None")
return status_check
if( x_change > 0 and column > width-len(word) ):
status_check.append(False)
status_check.append("None")
return status_check
if( y_change < 0 and row < len(word) ):
status_check.append(False)
status_check.append("None")
return status_check
if( y_change > 0 and row > height-len(word) ):
status_check.append(False)
status_check.append("None")
return status_check
# Now check to make sure there isn't another letter in our way
current_column=column
current_row=row
for letter in word:
# Make sure it is blank, or already the correct letter.
if grid[current_row][current_column]==letter or grid[current_row][current_column]=='.':
current_row += y_change
current_column += x_change
else:
# Oh! A different letter is already here. Fail.
status_check.append(False)
status_check.append("None")
return status_check
# Everything is good so far, actually place the letters.
current_column=column
current_row=row
for letter in word:
grid[current_row][current_column]=letter
current_row += y_change
current_column += x_change
if 7 in DirectionList:
status_check.append(True)
status_check.append("True")
return status_check
else:
status_check.append(True)
status_check.append("None")
return status_check
# This just calls tryToPlaceWord until we succeed. It could
# repeat forever if there is no possible place to put the word.
def placeWord(grid,words):
for word in words:
succeed=False
while not(succeed):
status_check=tryToPlaceWord(grid,word)
succeed=status_check[0]
backward = status_check[1]
return backward
# Create an empty grid
grid = createGrid()
# A list of words
words = ["pandabear","fish","snake","porcupine","dog","cat","tiger","bird","alligator","ant","camel","dolphin"]
# Place some words
placeWord(grid,words)
backward = placeWord(grid,words)
print("Current status:\n"
"\tGenerating a word searching diagram...\n"
"\tWords :",len(words),"\n"
"\tBackword :",backward)
# Print it out
printGrid(grid)
Then, I want to make the code print out random letters instead of dots(.) So I made some little changes.
import random
import string
DirectionList = []
# Create a grid filled random letters representing a blank
def createGrid():
grid=[]
for row in range(15):
grid.append([])
for column in range(50):
grid[row].append(random.choice(string.ascii_uppercase))
return grid
But python stops functioning, it prints out nothing for a long time. I thought maybe python needed a lot of time to generate 15 x 50 random letters, so I changed the code to grid[row].append("a"), but python is still not functioning.
What had gone wrong?
Edit:
Changed the code to
for letter in word:
# Make sure it is blank, or already the correct letter.
if grid[current_row][current_column]==letter or grid[current_row][current_column]==' ':
current_row += y_change
current_column += x_change
But the code is still hanging...
You use '.' also to check that a cell is free in your grid (line 87), so if you fill cells with random letters, they won't be free anymore. You could instead fill empty spaces with random letters after putting in the words...
Related
Recently, I've been working on a battleship game for my CS2 class. The focus of this project is to create a board game using arrays, and I decided to create a battleship. I have most of the code, but I cannot figure out how to get ships to get randomly generated on a 10x10 array without the ships being...
A. The wrong length
B. Looping around the array
Below is the function I currently have.
def createShips(board):
shipLen = [5,4,3,3,2]
shipAvalible = 5
directionposibilities = ["vertical", "horizontal"]
j = 0
for i in range(shipAvalible):
boatMade = False
#REGULAR VAR STATMENTS
direction = random.choice(directionposibilities)
col = randint(0,9)
row = randint(0,9)
while boatMade == False:
if direction == "vertical":
buildCount = 0
if col + int(shipLen[i]) <= 11:
colission = False
for i in range(0, int(shipLen[i])):
buildCount += 1
if board[int(row-i)][int(col)-1] == "X":
if colission:
pass
else:
colission = True
if colission:
col = randint(0,9)
row = randint(0,9)
else:
for j in range(buildCount):
board[int(row-j)][int(col)-1] = "X"
boatMade = True
else:
col = randint(0,9)
row = randint(0,9)
if direction == "horizontal":
if col + int(shipLen[i]) <= 10:
colission = False
buildCount = 0
for i in range(0, int(shipLen[i])):
buildCount += 1
if board[int(row)][int(col)+i-1] == "X":
if colission:
pass
else:
colission = True
if colission:
col = randint(0,9)
row = randint(0,9)
else:
for j in range(buildCount):
board[int(row)][int(col)+j-1] = "X"
boatMade = True
else:
col = randint(0,9)
row = randint(0,9)
shipAvalible = shipAvalible - 1
return(board)
board = [["■"] * 10 for x in range(10)]
print(createShips(board))
If you have any idea why this may not work please let me know!
P.S. I am using another function that prints the array nicely, if you would like that for convenience, it is seen below:
def showBoard(board):
print(" A B C D E F G H I J")
print(" ------------------------------")
rownumb = 1
for r in board:
if rownumb == 10:
space = ""
else:
space = " "
print("%d|%s|" % (rownumb, space + "|".join(r)))
rownumb += 1
Edit: #Eumel was a bit faster and said it better here
First of all, you have a inner and outer loop with the variable i, which might not actually interfere but it makes it harder to read the code. Consider renaming one of the variables.
When you create a vertical ship, you check the col rather than the row for index error, and does so against a value of 11 instead of your board size 10.
In the vertical case you build the ship "backwards" from the selected position, even though you checked that your board could fit the ship in the positive direction (And you place it in a column to the left). These negative values makes it such that your ships can wrap around.
In the horizontal case you are indexing a bit strange again where board[int(row)][int(col)+i-1] this gives that when i=0 you place your ship an index further to the left than intended, again causing the ship to wrap when col=0.
Further more, you could remove a few redundant if statements and duplicate lines of code, by moving:
direction = choice(directionposibilities)
col = randint(0, 9)
row = randint(0, 9)
Inside the while loop.
Ok lets go over this:
length check
if col + int(shipLen[i]) <= 9: since arrays start at 0 in python the maximum index for a 10x10 board is 9, therefore you need to chek against 9 instead of 11
loop variables
for k in range(0, int(shipLen[i])): using the same variable name for the outer and inner loop (while working in this specific case) is really bad form
collision check
if board[row+k][col] == "X": you want to build the ships "forwards" so you use row+k, you can also forego int conversions when you only use integers to begin with
collsion check 2
if colission: pass else: colission = True This whole block can be shortened to collision = True break since you dont need to keep checking for multiple collisions
buildcount
for j in range(buildCount): unless you get a collision (then you wouldnt be in this branch) buildCount is always the same as shipLen[i] so it can be completly removed from your code
boat building
board[row+j][col] = "X": same as before we build forwards
honorable mentions
shipAvailable = len(shipLen) you could also remove this part completly and iterate over your ships directly in your out for loop
Instead of radoomising your direction row and col on every break condition you could randomize it once at the start of your while loop
j = 0 unlike C you dont have to define your variables before using them in a loop, this statement does nothing
I'm trying to create Tetris for an university project. But I'm having a quite difficult time on doing the collisions. Actually, they work, until I try to rotate a piece. After I rotate a piece the collision always returns True.
This is the code:
def constraint(self):
if self.shape_y + len(self.shape) == configuration.config['rows']:
return True
for shape_row, row in enumerate(self.shape):
column_index = -1
for x in range(self.shape_x, self.shape_x + len(self.shape[0])):
column_index += 1
if self.shape[shape_row][column_index] != 0:
if shape_row+1 < len(self.shape):
if self.shape[shape_row+1][column_index] == 0:
if self.board.board[self.shape_y + 1][x] != 0:
return True
else:
if self.board.board[self.shape_y + len(self.shape)][x] != 0:
print("qui")
return True
return False
shape_y is the row where the shape is located. len(self.shape) returns how many rows is the shape because it's coded like a matrix:
Example:
[[0, 1, 0],
[1, 1, 1]],
Is the piece with one block on top and three under.
Shape is the matrix that represent the piece.
Shape_x is the column where the shape is located.
The board is a matrix like this:
self.board = np.array([[0 for _ in range(configuration.config["cols"])]
for _ in range(configuration.config['rows'])])
where 0 is free, others numbers are block that are not free.
Here a screenshot that show the problem:
The blue and the green pieces get stuck like a collision occurred but are in "mid air" and nothing really occurred.
EDIT1:
This is the code for the rotation
def rotate(self):
self.board.remove_piece(self)
self.shape = np.rot90(self.shape)
self.board.add_piece(self)
Where self.board.remove_piece(self) and self.board.add_piece(self) just remove and add the values inside the board so that i can draw it again. So, basically, the rotation code is just self.shape = np.rot90(self.shape)
I should have actually fixed the problem, the error was inside an index to check on the board.
def constraint(self):
if self.shape_y + len(self.shape) == configuration.config['rows']:
return True
for shape_row, row in enumerate(self.shape):
column_index = -1
for x in range(self.shape_x, self.shape_x + len(self.shape[0])):
column_index += 1
if self.shape[shape_row][column_index] != 0:
if shape_row+1 < len(self.shape):
if self.shape[shape_row+1][column_index] == 0:
if self.board.board[self.shape_y + shape_row + 1][x] != 0:
return True
else:
if self.board.board[self.shape_y + len(self.shape)][x] != 0:
return True
return False
I have programmed a program of tic tac toe in python where I use the following code to determine if a row / column / diagonal consists of only ones or twos to determine if any of player one or two have won (I use ones and twos instead of x and o). The problem is that I want the winner to be chosen when there are three in a row regardless of the size of the board and with this code this only works for a board of size 3x3.
def check_row(board, player):
'''
Checks row for a win
'''
return any(all(row == player)
for row in board)
def check_column(board, player):
'''
Checks column for a win
'''
# We use transpose() to be able to check the column by using the definition
# for check_row
return check_row(board.transpose(), player)
def check_diagonal(board, player):
'''
Checks diagonal for a win
'''
# We use np.diag() and np.fliplr() to be able to check the diagonals
# of the game board
return any(all(np.diag(board_rotation) == player)
for board_rotation in [board, np.fliplr(board)])
For example, if I choose a board with size 5x5, the winner will be, with this code, when it is five in a row and not three in a row. I use np.zeros ((board_size, board_size), dtype = int) to create a game board and I have considered whether you can use something like column_1 == column_2 == column_3 to determine if there are three in a row:
if board[1][1] != 0:
if board[1][1] == board[0][0] == board[2][2]:
return board[1][1]
elif board[1][1] == board[0][2] == board[2][0]:
return board[1][1]
But also for this to work in a 5x5 game board I have to write down all possible ways to get three in a row in a 5x5 board which will give an extremely long code. Any tips to improve this?
This is my fully code now:
''' 403-0047-MPO '''
import numpy as np
import random
import matplotlib.pyplot as plt
# scenario = What scenario you would like to play, scenario one or scenario two
# game_size = The size of game board, 3x3, 5x5 or 7x7
# games = The number of game rounds you would like to play
# board = The game board
def create_board(board_size):
'''
Creating an empty board
'''
return np.zeros((board_size,board_size), dtype=int)
def available_spaces(board):
'''
Looking for available spaces on the game board
This is used in both scenario one and two
'''
lst = []
for i in range(len(board)):
for j in range(len(board)):
if board[i][j] == 0:
lst.append((i, j))
return(lst)
def make_random_move(board, player):
'''
Randomly places the player's marker on the game board
This is used in both scenario one and two
'''
spaces = available_spaces(board)
space = random.choice(spaces)
board[space] = player
return board
def available_space_middle(board, board_size):
'''
Checks that the center position is available for all game boards
This is only used in scenario two
'''
# Using if-statements to find the middle for all board_size ∈ {3, 5, 7}
# and check that they are empty, this also avoids placing the marker there repeatedly.
lst = []
for i in range(len(board)):
for j in range(len(board)):
if board_size == 3:
if board[i][j] == 0:
lst.append((1, 1))
if board_size == 5:
if board[i][j] == 0:
lst.append((2, 2))
if board_size == 7:
if board[i][j] == 0:
lst.append((3, 3))
return(lst)
def make_move_middle(board, player, board_size):
'''
Places the first marker for player one in the center of the game board.
This is only used in scenario two
'''
# Using player = 1 we define that the first move in scenario two should be
# made by player one using the marker 1
player = 1
selection = available_space_middle(board, board_size)
current_loc = random.choice(selection)
board[current_loc] = player
return board
def check_row(board, player):
'''
Checks row for a win
'''
return any(all(row == player)
for row in board)
def check_column(board, player):
'''
Checks column for a win
'''
# We use transpose() to be able to check the column by using the definition
# for check_row
return check_row(board.transpose(), player)
def check_diagonal(board, player):
'''
Checks diagonal for a win
'''
# We use np.diag() and np.fliplr() to be able to check the diagonals
# of the game board
return any(all(np.diag(board_rotation) == player)
for board_rotation in [board, np.fliplr(board)])
def evaluate(board):
'''
Evaluates the game board for a winner
'''
# Here we bring out the winner and define 1 for when player one wins,
# 2 for when player two wins and -1 for ties.
winner = 0
for player in [1, 2]:
if (check_row(board, player) or
check_column(board,player) or
check_diagonal(board,player)):
winner = player
if np.all(board != 0) and winner == 0:
winner = -1
return winner
def play_game(scenario, board_size):
'''
Defines the game for scenario one and scenario two
'''
# By using if-statements and a while-loop we define how the game should
# go in scenario one and scenario two respectively.
# By using break, we also ensure that the loop (game) ends if a winner has been found.
board, winner, counter = create_board(board_size), 0, 1
if scenario == 1:
while winner == 0:
for player in [1, 2]:
board = make_random_move(board, player)
# Remove the hashtags below to check the game board step by step
print("Board after " + str(counter) + " move")
print(board)
counter += 1
winner = evaluate(board)
if winner != 0:
break
return winner
if scenario == 2:
while winner == 0:
for player in [2, 1]:
board = make_move_middle(board, player, board_size)
board = make_random_move(board, player)
# Remove the hashtags below to check the game board step by step
print("Board after " + str(counter) + " move")
print(board)
counter += 1
winner = evaluate(board)
if winner != 0:
break
return winner
def save_stats(games, scenario, board_size):
'''
Saves data from all game rounds
'''
# By using the previously defined 1,2 and -1 we add one point for each win
# for player1wins, player2wins and ties.
player1wins=0
player2wins=0
ties=0
for game in range(games):
result=play_game(scenario, board_size)
if result==-1: ties+=1
elif result==1: player1wins+=1
else: player2wins+=1
return [player1wins, player2wins, ties] # for returning
def print_stats(games, scenario, board_size):
'''
Presents data from all game rounds
'''
player1wins, player2wins, ties = save_stats(games, scenario, board_size)
print('Player 1 wins:',player1wins)
print('Player 2 wins:',player2wins)
print('Tie:',ties)
# Data
height = [player1wins, player2wins, ties]
bars = ('Player 1', 'Player 2', 'Tie')
y_pos = np.arange(len(bars))
# Create bars and choose color
plt.bar(y_pos, height, color = (0.5,0.1,0.5,0.6))
# Limits for the Y axis
plt.ylim(0,games)
# Create names
plt.xticks(y_pos, bars)
# Saves a pdf with data
plt.savefig('utfall.pdf') # Saves the data as 'utfall.pdf'
plt.close()
def main():
'''
This is the main body of the program
'''
# Using try: and except: to raise ValueError and
# while-loops to handle incorrect input. The question will be asked again
# if the input value is wrong and continue via break if it is correct.
try:
while True:
games = int(input("How many games do you want to simulate? "))
if games <1:
print('The number of game rounds should be grater than zero, try again')
else:
break
while True:
board_size = int(input("How big playing surface (3/5/7)? "))
if not (board_size == 3 or board_size == 5 or board_size == 7):
print('Board size does not exist, try again')
else:
break
while True:
scenario = int(input('What scenario (1/2)? '))
if not (scenario == 1 or scenario == 2):
print('Scenario does not exist, try again')
else:
break
print_stats(games, scenario, board_size)
except ValueError:
print('All questions must be answered correctly for the game to start, try again')
main()
I will post a idea using numpy.split
You split your board in chunks of 3, but starting in different positions: 0, 1 and 2.
Explanation: Consider [a,b,c,d,f,g]
Starting from 0 -> [a,b,c], [d,f,g]
Starting from 1 -> [b,c,d]
Starting from 2 -> [c,d,f]
so, all possibilities are there
You check if the elements are equal 1 or 2 and sum over the boolean mask. If the sum is 3, then there is a chunk with 3 equal elements.
Example code to search from winners on the rows:
import numpy as np
#random array just for test
board = np.array([[1,-1,-1,-1,1,0],
[1,1,0,1,1,0],
[1,1,0,1,1,0],
[1,1,0,1,1,0],
[1,1,0,1,1,0]])
winner = None
#iterate on i to start from position 0, 1 and 2
for i in range(3):
#We want the lengh of the array a multiple of 3, so we must correct were it ends:
rest = -(board[:,i:].shape[1]%3)
if rest == 0:
#0 would return a empty list, so if it is the case, we will change to None
rest = None
#Now, we calculate how manny divisions we need to get chunks of 3 (on the rows)
n = (board[:,i:].shape[1])//3
#Now divide the board in chunks
chunks = np.split(board[:,i:rest],n,axis = 1)
for matrix in chunks:
#sum over all rows of 3 elements
sumation = np.sum(matrix == 1,axis = 1)
if 3 in sumation:
winner = 1
sumation = np.sum(matrix == 2,axis = 1)
if 3 in sumation:
winner = 2
Well, maybe a little confusing, but i believe it will work, or at least give you some idea
I'm making a chess program and as such need the program to tell me what piece I have clicked on. So far it tells me if I've clicked on any piece at all, by matching rounded mouse x and y coordinates to a list of current piece coordinates. However, the program doesn't know what exact piece I've clicked, and I'm wondering if using a while loop I can make the loop end when a piece is found, and print/store the section of the list I was on when I found a matching piece to my mouse coords.
Currently I've got this code, which should be a good starting point for my problem
if event.type == pygame.MOUSEBUTTONDOWN:
mousepos = pygame.mouse.get_pos()
#rounddown80 is a function to round down mouse coords to multiple of 80
roundedmouse1 = roundup80(mousepos[0])
roundedmouse2 = roundup80(mousepos[1])
#print(roundedmouse1,roundedmouse2)
mousecoords = [roundedmouse1,roundedmouse2]
#print(mousecoords)
foundpiece = False
while foundpiece == False:
for x in piecespositions:
if x[0] == mousecoords[0] and x[1] == mousecoords[1]:
print("Great job you clicked a piece")
foundpiece = True
And my piecepositions list looks like
piecespositions = [queenblackpos,kingblackpos,bishop1blackpos,bishop2blackpos,knight1blackpos,knight2blackpos,
etc for all pieces, and queenblackpos for example would be [80,160]
You can keep track of what piece you are on inside the while loop, either in for i in range(0,len(piecepositions)) or with a variable that increases.
For example something like this:
while foundpiece == False:
index=0 #Reset index before checking all pieces
for x in piecespositions:
if x[0] == mousecoords[0] and x[1] == mousecoords[1]:
print("Great job you clicked a piece")
foundpiece = True
found_pos=x #store position of the piece that was found
index=index+1 #Keep adding to index to know which piece was found
pygame.display.flip() #Update the window
print (f"Piece found in {index}: {found_pos}") #print the position of the piece as well as what is its index in the list.
This will store the position of the piece that was found in found_pos and keep track of which piece is being checked at the moment using index var. After the while loop ends it prints out the position of the piece and the index of that piece in the list.
Do note though, during the while loop the script will be "stuck" until the while is finished, so it will be unable to update the window during the piece check therefore the game will freeze. So to solve this, you have to add pygame.display.flip() inside the while.
I did something like this. Hope that it will help You:
square_s = 160 # square(tile) size - you can pass your value
letters = ["A", "B", "C", "D", "E", "F", "G", "H"] # letters used in pos symbols
# match each tile on board to the right cords symbol and value(x, y)
def matchSqrCords(sqr_s, letters):
positions = [] # matched positions
for y in range(8): # for each row on the board
for x in range(8): # for each column(tile in a row) on the board
pos = ["", 0, 0] # curr position
pos[0] += letters[y] # add letter prefix to pos symbol
pos[0] += str(x + 1) # add number prefix to pos symbol
pos[1] = sqr_s*(x + 1) # calc max x range of a tile
pos[2] = sqr_s*(y + 1) # calc max y range of a tile
positions.append(pos) # add matched pos to list
return positions # return list with matched positions
def checkPosition(given_cords, cords, sqr_s):
# check if typed values are on the board
if given_cords[0] > sqr_s * 8 or given_cords[1] > sqr_s * 8:
return "Cords not on the board!"
else:
for cord in cords: # check all cords
# check if given cords x value is in range of curr cord
if given_cords[0] <= cord[1] and given_cords[0] > cord[1] - sqr_s:
# check if given cords y value is in range of curr cord
if given_cords[1] <= cord[2] and given_cords[1] > cord[2] - sqr_s:
return cord[0] # return symbol of the found cord
matched_pos = matchSqrCords(square_s, letters=letters)
print(checkPosition([192, 569], matched_pos, square_s))
I am implementing a Python version of the game Othello / Reversi. However, my algorithm seems to be having trouble when searching in the southwest direction.
Here are some important functions to understand how my current code works:
def _new_game_board(self)->[[str]]:
board = []
for row in range(self.rows):
board.append([])
for col in range(self.columns):
board[-1].append(0)
return board
def _is_valid_position(self, turn:list)->bool:
'''return true if the turn is a valid row and column'''
row = int(turn[0]) - 1
column = int(turn[1]) - 1
if row >= 0:
if row < self.rows:
if column >= 0:
if column < self.columns:
return True
else:
return False
def _is_on_board(self, row:int, col:int)->bool:
'''returns true is coordinate is on the board'''
if row >=0:
if row < self.rows:
if col >=0:
if col < self.columns:
return True
def _searchNorthEast(self)->None:
'''Search the board NorthEast'''
print("NorthEast")
row = self.move_row
column = self.move_column
should_be_flipped = list()
row += 1
column -= 1
if self._is_on_board(row, column):
print("column searching NorthEast on board")
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
while True:
row += 1
column -= 1
if self._is_on_board(row, column):
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
continue
elif self.board[row][column] == self.turn:
self._to_be_flipped.extend(should_be_flipped)
break
else:
break
else:
self._to_be_flipped.extend(should_be_flipped)
else:
pass
def _searchSouthWest(self)->None:
'''Search the board SouthWest'''
print("in SouthWest")
row = self.move_row
column = self.move_column
should_be_flipped = list()
row -= 1
column += 1
if self._is_on_board(row, column):
print("column searching SouthWest on board")
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
while True:
row -= 1
column += 1
if self._is_on_board(row, column):
if self.board[row][column] == self._opponent:
should_be_flipped.append([row, column])
continue
elif self.board[row][column] == self.turn:
self._to_be_flipped.extend(should_be_flipped)
break
else:
break
else:
self._to_be_flipped.extend(should_be_flipped)
else:
pass
def _move_is_valid(self, turn:list)->bool:
'''Verify move is valid'''
self._to_be_flipped = list()
self._opponent = self._get_opposite(self.turn)
if self._is_valid_position(turn):
self.move_row = int(turn[0]) - 1
self.move_column = int(turn[1]) - 1
self._searchRight()
self._searchLeft()
self._searchUp()
self._searchDown()
self._searchNorthWest()
self._searchNorthEast
self._searchSouthEast()
self._searchSouthWest()
if len(self._to_be_flipped) > 0:
return True
else:
return False
Now let's say the current board looks like the following:
. . . .
W W W .
. B B .
. B . .
Turn: B
and the player makes a move to row 1 column 4, it says invalid because it does not detect the white piece in row 2 column 3 to be flipped. All my other functions are written the same way. I can get it to work in every other direction except in this case.
Any ideas why it is not detecting the piece in this diagonal direction?
Don't Repeat Yourself. The _search* methods are extremely redundant which makes it difficult to see that the signs in
row -= 1
column += 1
are correct. Since you've given only two directions (NE, SW) and no documentation of the board orientation, I cannot tell if the signs agree with the board layout or even agree with themselves.
The _search* methods are also too long and should be divided into multiple functions, but that's a secondary concern.
I agree with msw about not repeating stuff. It is tempting to go ahead and do what you can once you see it, but generalizing will save you the headaches of debugging.
Here is some pseudocode that should give the general idea. I might not be able to finagle working with your code, but hopefully this shows how to reduce repetitive code. Note it doesn't matter if -1 is up or down. The board class is simply a 2x2 array of (open square/player 1's piece/player 2's piece,) along with whose turn it is to move.
# x_delta and y_delta are -1/0/1 each based on which of the up to 8 adjacent squares you are checking. Player_num is the player number.
def search_valid(x_candidate, y_candidate, x_delta, y_delta, board, player_num):
y_near = y_candidate + y_delta
x_near = x_candidate + x_delta
if x_near < 0 or x_near >= board_width:
return False
if y_near < 0 or y_near >= board_width:
return False # let's make sure we don't go off the board and throw an exception
if board.pieces[x_candidate+x_delta][y_candidate+y_delta] == 0:
return False #empty square
if board.pieces[x_candidate+x_delta][y_candidate+y_delta] == player_num:
return False #same color piece
return True #if you wanted to detect how many flips, you could use a while loop
Now a succinct function can loop this search_valid to see whether a move is legal or not e.g.
def check_valid_move(x_candidate, y_candidate, board, player_num):
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
if not x and not y:
continue # this is not a move. Maybe we don't strictly need this, since board.pieces[x_candidate+x_delta][y_candidate+y_delta] == player_num anyway, but it seems like good form.
if search_valid(x_candidate, y_candidate, dx, dy, board, player_num):
return True
return False
A similar function could actually flip all the opposing pieces, but that's a bit trickier. You'd need a while function inside the for loops. But you would not have to rewrite code for each direction.