How do I fix this list being out of range? - python

I'm making a game in which the player can move on a 8x8 grid, but I'm getting an error in which the values are out of range.
Here is my code:
def player_movement():
grid0 = []
grid1 = []
i = 0
n = 0
while i < 8: #this makes the grid
grid0.append("0")
i += 1
while n < 8:
grid1.append(grid0.copy())
n += 1
grid1[0][0] = "X" # this places the player on the top left of the grid
for l in grid1:
print(l)
while True:
player_movex = int(input("Move right how many?"))# instructions to move the player
player_movey = int(input("Move down how many??"))
for y, row in enumerate(grid1): #this finds the player on the grid
for x, i in enumerate(row):
if i == "X":
grid1[y][x], grid1[y + player_movey][x + player_movex] = grid1[y + player_movey][x + player_movex], grid1[y][x]
for j in grid1: #prints out the grid in the 8x8 format
print(j)
and I am entering values that are within the lists' range i.e. 0-7.
This is the error that appears on my screen:
Traceback (most recent call last):
File "D:\Python\Treasure Hunt game.py", line 83, in <module>
player_movement()
File "D:\Python\Treasure Hunt game.py", line 78, in player_movement
grid1[y][x], grid1[y + player_movey][x + player_movex] = grid1[y + player_movey][x + player_movex], grid1[y][x]
IndexError: list index out of range

The reason being the loops are executed even after the movement is made.
def player_movement():
grid0 = []
grid1 = []
i = 0
n = 0
while i < 8: #this makes the grid
grid0.append("0")
i += 1
while n < 8:
grid1.append(grid0.copy())
n += 1
grid1[0][0] = "X" # this places the player on the top left of the grid
for l in grid1:
print(l)
while True:
player_movex = int(input("Move right how many?"))# instructions to move the player
player_movey = int(input("Move down how many??"))
done = False
for y, row in enumerate(grid1): #this finds the player on the grid
for x, i in enumerate(row):
if i == "X":
print(y, x)
grid1[y][x], grid1[y + player_movey][x + player_movex] = "0", "X"
done = True
if done == True:
break
if done == True:
break
for j in grid1: #prints out the grid in the 8x8 format
print(j)
player_movement();

I would rather code as follows:
def player_movement():
n = 8
grid = [['0'] * n for _ in range(n)]
m = 'x'
grid[0][0] = m # this places the player on the top left of the grid
for i in grid:
print(i)
while True:
# instructions to move the player
player_movex = int(input("Move right how many? "))
player_movey = int(input("Move down how many?? "))
move(grid, m, n, player_movey, player_movex)
for j in grid: # prints out the grid in the 8x8 format
print(j)
def move(grid, m, n, move_y, move_x):
for y, row in enumerate(grid): # this finds the player on the grid
for x, i in enumerate(row):
if i == m:
a, b = y + move_y, x + move_x
if a >= n:
print(f'Sorry, move {move_y} down will out of range!\n')
return
if b >= n:
print(f'Sorry, move {move_x} right will out of range!\n')
return
grid[y][x], grid[a][b] = grid[a][b], grid[y][x]
return
player_movement()

Related

Malfunctioning code for a MinMax-algorithm in python

I recently tried to code an AI to solve the connect-four game. I've come quite far but I am now stuck with a minor mistake in the code that I just cant locate. Generally the algorithm played great but sometimes the algorithms ignores a row of 3 pieces the opponent has which results in the loss of the algorithm. As you will see, I have constructed the evaluation function so that positions like that should be rated with a extremely low score, which it does. Also the score of a position where the algorithm has lost is always rated with -inf. Therefore I can't imagine why the algorithm would be unable to counter positions like that.
The bot relies on a framework which I can't upload here thus I am sorry that the code itself without changes cant be simply executed.
from aiagent import AiAgent
import math
import copy
import numpy as np
class MinMaxAgent(AiAgent):
def __init__(self):
'''
Creates the board.
'''
self.board = [[0,0,0,0,0,0],
[0,0,0,0,0,0],
[0,0,0,0,0,0],
[0,0,0,0,0,0],
[0,0,0,0,0,0],
[0,0,0,0,0,0],
[0,0,0,0,0,0]]
def getNextMove(self):
'''
Calculate the index of the player move and store it on the board. Return that value.
'''
self._getMinMax(board=self.board)
self.board[self.bestIndexCol][self._getRowIndex(self.bestIndexCol, self.board)] = 1
print(f'Eval: {self._evaluate(self.board)}')
return (self.bestIndexCol, self._getRowIndex(self.bestIndexCol, self.board))
def handleNextMove(self, indexCol):
'''
Store the index of the enemy move in the board.
'''
self.board[indexCol[0]][self._getRowIndex(indexCol[0], self.board)] = -1
print(f'Eval: {self._evaluate(self.board)}')
def _getRowIndex(self, indexCol, board):
'''
Get the index of the row of a column within a board.
'''
for indexRow, elementRow in enumerate(board[indexCol]):
if elementRow == 0:
return indexRow
def _getValidIndex(self, board):
'''
Get all the valid indices of a board.
'''
validMoves = []
for indexCol, col in enumerate(board):
if col.count(0) != 0:
validMoves.append(indexCol)
return validMoves
def _getMinMax(self, board, depth=6, player=1, alpha=-math.inf, beta=math.inf):
'''
Calculates the best move within a specific depth.
'''
if depth == 0:
return self._evaluate(board)
elif self._isTerminalState(board) == 0:
return self._evaluate(board)
elif self._isTerminalState(board) == -1:
return -math.inf
elif self._isTerminalState(board) == 1:
return math.inf
if player == 1:
resultMax = -math.inf
self.bestIndexCol = None
for indexCol in self._getValidIndex(board):
# Mutate the board
self.nextBoard = copy.deepcopy(board)
self.nextBoard[indexCol][self._getRowIndex(indexCol, board)] = 1
# Calls itself with a by one decremented depth and the change of player
self.resultMinMax = self._getMinMax(board=self.nextBoard, depth=depth-1, player=-1, alpha=alpha, beta=beta)
# Take the board state with the most amount of points
if self.resultMinMax > resultMax:
resultMax = self.resultMinMax
self.bestIndexCol = indexCol
# Change alpha if the boardstate is evaluated with more points
if self.resultMinMax > alpha:
alpha = self.resultMinMax
# Break the loop if on a alphaboundry
if alpha >= beta:
break
return resultMax
elif player == -1:
resultMin = math.inf
for indexCol in self._getValidIndex(board):
# Mutate the board
self.nextBoard = copy.deepcopy(board)
self.nextBoard[indexCol][self._getRowIndex(indexCol, board)] = -1
# Calls itself with a by one decremented depth and the change of player
self.resultMinMax = self._getMinMax(board=self.nextBoard, depth=depth-1, player=1, alpha=alpha, beta=beta)
# Take the board state with the least amount of points
if self.resultMinMax < resultMin:
resultMin = self.resultMinMax
# Change beta if the boardstate is evaluated with less points
if self.resultMinMax < beta:
beta = self.resultMinMax
# Break the loop if on a betaboundry
if alpha >= beta:
break
return resultMin
def _isTerminalState(self, board):
'''
Checks the board for a terminal state of the board:
Return: 0 for a draw;
1 for a victory;
-1 for a defeat;
'''
# Evaluate draw
if [board[col].count(0) for col in range(7)] == [0,0,0,0,0,0,0]:
return 0
# Evaluate vertical for terminal state
for col in range(7): # columns
for row in range(3): # rows
if [board[col][row + i] for i in range(4)] == [1,1,1,1]:
return 1
elif [board[col][row + i] for i in range(4)] == [-1,-1,-1,-1]:
return -1
# Evaluate horizontal for terminal state
for col in range(4): # columns
for row in range(6): # rows
if [board[col + i][row] for i in range(4)] == [1,1,1,1]:
return 1
elif [board[col + i][row] for i in range(4)] == [-1,-1,-1,-1]:
return -1
# Evaluate diagonal for terminal state
for col in range(4): # columns
for row in range(3): # rows
if [board[col + i][row + i] for i in range(4)] == [1,1,1,1]:
return 1
elif [board[col + i][row + i] for i in range(4)] == [-1,-1,-1,-1]:
return -1
for col in range(4): # columns
for row in range(3, 6): # rows
if [board[col + i][row - i] for i in range(4)] == [1,1,1,1]:
return 1
elif [board[col + i][row - i] for i in range(4)] == [-1,-1,-1,-1]:
return -1
def _evaluateSection(self, section):
'''
Evaluates every section of the board and adds points according to the amount of elements of the same actor in a section:
PLAYER: 4-in-a-row: +inf
ENEMY: 4-in-a-row: -inf
PLAYER: 3-in-a-row: +1000
ENEMY: 3-in-a-row: -3000
PLAYER: 2-in-a-row: +200
ENEMY: 2-in-a-row: -600
'''
self.section_evaluation = 0
if section.count(1) == 4:
self.section_evaluation += math.inf
elif section.count(-1) == 4:
self.section_evaluation -= math.inf
elif section.count(1) == 3 and section.count(0) == 1:
self.section_evaluation += 1000
elif section.count(-1) == 3 and section.count(0) == 1:
self.section_evaluation -= 3000
elif section.count(1) == 2 and section.count(0) == 2:
self.section_evaluation += 200
elif section.count(-1) == 2 and section.count(0) == 2:
self.section_evaluation -= 600
return self.section_evaluation
def _evaluate(self, board):
'''
Takes sections of the board to evaluate.
'''
self.evaluation = 0
# Evaluate vertical sections
for col in range(7): # columns
for row in range(3): # rows
self.section = [board[col][row + i] for i in range(4)]
self.evaluation += self._evaluateSection(self.section)
# Evaluate horizontal sections
for col in range(4): # columns
for row in range(6): # rows
self.section = [board[col + i][row] for i in range(4)]
self.evaluation += self._evaluateSection(self.section)
# Evaluate diagonal sections
for col in range(4): # columns
for row in range(3): # rows
self.section = [board[col + i][row + i] for i in range(4)]
self.evaluation += self._evaluateSection(self.section)
for col in range(4): # columns
for row in range(3, 6): # rows
self.section = [board[col + i][row - i] for i in range(4)]
self.evaluation += self._evaluateSection(self.section)
return self.evaluation
I already redesigned the evaluation function and checked the minmax-algorithm which should include all the possible sources of this error but I wasn't able to find any satisfying answer.

Connect-N Game in Python needs Winner function

Python Code Connect-N Game.
Hi there, I need help with detecting the winner for the 8 directions in Connect N. The game is like Connect 4, but the user inputs N to whatever they want it to be. So could be Connect 5, or 6, etc. However, at the moment, my code is not detecting the 8 directions. I really am struggling with this function. Can someone show me how some code that would work to apply into my def have_winner function.
Thank you!
Instructions for the game
# GLOBAL VARIABLES
N = 5
num_row = N + 3
num_col = N + 2
disk = ['\u2B1C', '\u26AA', '\u26AB']
board = []
def init_board(n):
'''initialise the board'''
global N, num_row, num_col
N = n
num_row = n + 3
num_col = n + 2
for c in range(num_col):
board.append([0]*num_row)
def display():
'''print the board'''
to_print = " "
for i in range(num_col):
to_print = to_print + f'[{i}]'
print(to_print)
for i in range(num_row):
to_print = f'[{i:2}]'
for j in range(num_col):
to_print = f'{to_print}{disk[board[j][i]]:2}'
print(to_print)
def game():
'''play the game'''
n = input('Please input N:')
init_board(int(n))
p = 0
while True:
c = input(f'Player {p} select colomn:')
if c == 'q': # quit the game
print(f'Player {p} resigned')
break
# drop disk
f = drop_disk(int(c), p+1)
if f == 0: # illegal move
print(f'Column {c} is an illegal move')
continue
display()
# check winner and switch side
w = have_winner()
if w == 1:
print(f'Player {p} won')
break
elif w == 2:
print('draw')
break
else:
p = (p + 1)%2
def drop_disk(c, player):
"""player drop a disk at ch colomn. Return 1 if successfully drop the disk, return 0 if this is a illegal move, e.g. the colomn is full."""
if board[c][0] != 0:
return 0
for r in range(num_row -1, -1, -1):
if board[c][r] == 0:
board[c][r] = player
return 1
return 0
def have_winner():
"""return 1 if there is a winner, return 2 if the board is full, return 0 otherwise"""
for c in range(num_col):
for r in range(num_row):
if board[c][r] == 0:
return 0
return 2
# MAIN CODE
game()

Why am I getting the variable not defined error?

The following is my code
n = int(input("please enter a value: "))
board = []
def make_board(n):
global board
max = n * n #the number of tiles in the board
count = 1 #a counter to change the value assigned to each tile
for i in range(n):
board.append([]) #appends a list inside the list of board. Essentially creates a row which is of type list.
for j in range(n):
num = max - count
if num == 0: #the 0 tile will display like a blank space
tile = ' '
elif num < 10: #adds a space to tile values less than 10 for formatting.
tile = ' ' + str(num)
else:
tile = str(num)
board[i].append(tile) #appends a tile value to each row, n number of times.
count += 1
if n%2 == 0:
tempvara = board[n-1][n-2]
tempvarb = board[n-1][n-3]
board[n-1][n-2]=tempvarb
board[n-1][n-3]=tempvara
#TODO
for row in board:
print(' '.join(row))
def find_blank(board):
global counterUNO
global counterDOS
global counterTRES
counterTRES = 0
#TODO
for i in range(n):
tempvari = board[i]
if ' ' in tempvari:
counterUNO = i
for z in board[counterUNO]:
counterTRES = counterTRES + 1
if ' ' in z:
counterDOS = counterTRES-1
break
tupleone = (counterUNO,counterDOS)
return(tupleone)
def find_tile(f):
counterfour = 0
tiles = str(input("tile BUBBER"))
if int(tiles)<10:
tiles = " "+tiles
counterfive = 0
countersixe = 0
countersixe = 0
for i in range(n):
chopstick = board[i]
if tiles in chopstick:
counterfour = i
for z in board[counterfour]:
countersixe = countersixe + 1
if tiles in z:
counterfive = countersixe-1
break
tupleDOS = (counterfour,counterfive)
return(tupleDOS)
def find_next_to_blank(board):
#print("here is the shit")
#print(find_tile(board))
vara = find_tile(board) #sets tile numb tuple to vara
varb = find_blank(board) #yeah
varc = int(tiles)
varaa = int(tiles[0])
varab = int(tiles[1])
varba = board[varaa+1][varab]
varbb = board[varaa][varab+1]
varbc = board[varaa-1][varab]
varbd = board[varaa][varab-1]
varbe = board[varaa+1][varab+1]
varbf = board[varaa-1][varab-1]
make_board(n)
#find_blank(board)
#find_tile(board)
find_next_to_blank(board)
Problem:
Right now I am trying to make a python Tile game where I can shift the numbers. the make board function obviously creates a board, i did it so that there are three lists in a big list and in the three list there are elements
and the find blank function identifies the coordinate of the non existing section of the board
and the find tile function is the function that the user inputs a value and the code identifies what is the coordinate of the tile that we want
So currently I am getting an error because when i am running the find next to blank function (the function is supposed to identify whether or not there is a blank spot next to the value which the user wants to input) i get the following error
Traceback (most recent call last):
File "python", line 149, in <module>
File "python", line 122, in find_next_to_blank
NameError: name 'tiles' is not defined
and i tried making "tiles" variable into a global one but it didn't work at all
The variable tiles is not defined in find_next_to_blank(board). I'd be remiss if I don't say this: consider restructuring your program to avoid using global variables.
Now that's out of the way, if you make tiles global, it ought to work.

Python Game of Life, only alive cells is in the corners

I'm currently working on making a Game of Life program (UNI related, beginner course), by using nested lists.
However I can't seem to get the update() method to work properly, I've no clue what's wrong. The generation of the first board is okay, but the update leaves only the cornercells alive, and the rest dead.
All methodcalls in this class originates from other .py files, which works well.
from random import randint
from cell import *
class Spillebrett:
def __init__(self, rows, columns):
self.genNumber = 0
self._rows = rows
self._columns = columns
self._grid = []
for i in range(self._rows):
self._grid.append([])
for j in range(self._columns):
self._grid[i].append(cell())
self.generate()
def drawBoard(self):
for i in self._grid:
print(" ".join(map(str, i)))
print()
#Method updates genNumber, checks if cells are alive or dead and updates the board accordingly
#Currently only yield board with corner-cells alive
def updateBoard(self):
self.genNumber += 1
toLive = []
toDie = []
for x, row in enumerate(self._grid):
for y, cell in enumerate(rad):
if cell.areAlive() is True:
counter = len(self.findNeighbour(x, y))
if counter < 2 or counter > 3:
toDie.append(cell)
elif counter == 2 or counter == 3:
toLive.append(cell)
elif cell.areAlive() is False:
counter = len(self.findNeighbour(x, y))
if counter == 3:
toLive.append(cell)
for i in toDie:
i.setDead()
for i in toLive:
i.setAlive()
return self.genNumber
#Code given by Uni
def generate(self):
for i in range(self._rows):
for j in range(self._columns):
rand = randint(0, 3)
if rand == 3:
self._grid[i][j].setAlive()
#Code given by Uni
def findNeighbour(self, row, column):
neighbourList = []
for i in range(-1, 2):
for j in range(-1, 2):
neighbourRow = rad + i
neighbourcolumn = column + j
if(neighbourRow == rad and neighbourcolumn == column) is not True:
if(neighbourRow < 0 or neighbourcolumn < 0 or neighbourRow >
self._rows - 1 or neighbourcolumn > self._columns - 1) is not True:
neighbourList.append(self._grid[neighbourRow][neighbourcolumn])
return neighbourList
def findAllAlive(self):
self._alive = 0
for i in range(self._rows):
for j in range(self._columns):
if self._grid[i][j].areAlive() is True:
self._alive += 1
return self._alive

Problems with for loops for Tile Mapping in Python

I'm trying to generate a large tile map which is then going to be displayed on the screen. The map should be random, and only consists of two types of tiles at the moment.
However, what happens now is that each row of the Tile Map is overwritten with the first row from the heightmap, so that my map displays straight line columns of similar tiles when it displays.
I believe this is due to how I wrote my for loops, where it iterates through the entire heightmap, before even reaching the second list of tiles. Although due to the somewhat random element of tile choice that I tried to include, there should be at least some noise introduced to the map, but it seems like there isn't any.
Here is a link to a screenshot of what displays when I run my code.
import pygame, random
class Map(object):
MAPWIDTH = 64
MAPHEIGHT = 48
HEIGHTS = [0, 1, 2, 3, 4, 5, 6, 7, 8]
def __init__(self):
self.heightmap = [[random.choice(self.HEIGHTS) for w in range(self.MAPWIDTH)] for h in range(self.MAPHEIGHT)]
self.Tiles = [['' for w in range(self.MAPWIDTH)] for h in range(self.MAPHEIGHT)]
for rows in self.Tiles:
for row in self.heightmap:
i = 0
for height in row:
# 100% water block
if height == 0:
rows[i] = 'WATER'
# 70% water block
if height == range(1, 3):
if random.randint(0, 9) == range(0, 6):
rows[i] = 'WATER'
else:
rows[i] = 'GRASS'
# 50% water block
if height == 4:
if random.random() == 0:
rows[i] = 'WATER'
else:
rows[i] = 'GRASS'
# 80% grass block
if height == range(5, 7):
if random.randint(0, 9) == range(0, 6):
rows[i] = 'GRASS'
else:
rows[i] = 'WATER'
# 100% grass block
if height == 8:
rows[i] = 'GRASS'
i += 1
You write a lot of lines like:
if height == range(1, 3):
but that does not do what you think it does.
range(1, 3) returns the list [1, 2] (or an iterable that yields 1 and 2 if you're using python3), and that is never equal to a single integer.
You probably want to use a pattern like:
if height == 1 or height == 2
or
if 1 <= height <= 2:
or
if height in range(1, 2):
Nonetheless, you could simplify your code by creating a helper function that returns the chance of a grass tile for a given height:
def chance_of_grass(height):
if height == 0: return 0
elif height <= 3: return 30
elif height <= 4: return 50
elif height <= 7: return 80
return 100
and call that in your loop:
def __init__(self):
self.heightmap = [[random.choice(self.HEIGHTS) for w in range(self.MAPWIDTH)] for h in range(self.MAPHEIGHT)]
self.Tiles = [['' for w in range(self.MAPWIDTH)] for h in range(self.MAPHEIGHT)]
r_i = 0 # index of row
for h_row in self.heightmap:
c_i = 0 # index of column
for height in row:
is_grass = change_of_grass(height) >= random.randint(1, 100)
self.Tiles[r_i][c_i] = 'GRASS' if is_grass else 'WATER'
c_i += 1
r_i += 1
self.heightmap = [[random.choice(self.HEIGHTS) for w in range(self.MAPWIDTH)] for h in range(self.MAPHEIGHT)]
self.Tiles = [['' for w in range(self.MAPWIDTH)] for h in range(self.MAPHEIGHT)]
I'm not entirely sure what you're trying to do with that ^ but try this:
self.heightmap=[]
self.Tiles=[]
q=[]
for w in range(self.MAPWIDTH):
for h in range(self.MAPHEIGHT): q.append(random.choice(self.HEIGHTS))
self.heightmap.append(q)
q=[]
for w in range(self.MAPWIDTH):
for h in range(self.MAPHEIGHT): q.append('')
self.Tiles.append(q)
q=[]
for rows in self.Tiles:
for row in self.heightmap:
i = 0
for height in row:
rows.pop(i)
# 100% water block
if height == 0:
rows.insert(i,'WATER')
# 70% water block
if height in range(1, 3):
if random.randint(0, 9) in range(0, 6):
rows.insert(i,'WATER')
else:
rows.insert(i,'GRASS')
# 50% water block
if height == 4:
if random.random() > 0.5:
rows.insert(i,'WATER')
else:
rows.insert(i,'GRASS')
# 80% grass block
if height in range(5, 7):
if random.randint(0, 9) in range(0, 6):
rows.insert(i,'GRASS')
else:
rows.insert(i,'WATER')
# 100% grass block
if height == 8:
rows.insert(i,'GRASS')
i += 1

Categories

Resources