Issue with 2D array in python

Question:

I am working on a text-based chess project in python, and I have set up a pretty nice looking chess board in my output console. But whenever I try to place a piece somewhere, it fills up the entire file.

The code I used is here:

import os
global arrowKey
global speed
newchar = ''
arrowKey = {'x1b[A': 'up'}
class Pieces:
    Black_rook = '♜'
    Black_knight = '♞'
    Black_bishop = '♝'
    Black_queen = '♛'
    Black_king = '♚'
    Black_pawn = '♟︎'
    White_rook = '♖'
    White_knight = '♘'
    White_bishop = '♗'
    White_queen = '♕'
    White_king = '♔'
    White_pawn = '♙'
class Array:
    def __init__(self, x=16, y=8, board=None):
        self.pos = ()
        self.x = x
        self.y = y
        grid = [' ' + '_' * self.x]
        for _ in range(y):
            row = ['|']
            for _ in range(x):
                row.append(' ')
            row.append('|')
            grid.append(row)
        grid.append(' ' + '‾' * self.x)
        self.grid = grid
        if board != None:
            self.grid = board
    def reload(self, say=None):
        os.system('clear')
        if say != None:
            print(say)
        p = ''
        for i in self.grid:
            p = p + ''.join([x for x in i]) + 'n'
        print(p)
    def insert(self, char, x, y):
        self.pos = (x, y)
        self.grid[y][x] = char
    def move(self, direction, char):
        poslist = []
        for y, i in enumerate(self.grid):
            for x, j in enumerate(i):
                if j == char:
                    poslist.append((x, y))
        count = 0
        for posx, posy in poslist:
            if direction == 'down':
                if self.grid[posy + 1][posx] != '‾':
                    self.insert(' ', posx, posy)
                    self.insert(char, posx, posy + 1)
                    self.pos = (posx, posy + 1)
            if direction == 'up':
                if self.grid[posy - 1][posx] != '_':
                    self.insert(' ', posx, posy)
                    self.insert(char, posx, posy - 1)
                    self.pos = (posx, posy - 1)
            if direction == 'left':
                if self.grid[posy][posx - 1] != '|':
                    self.insert(' ', posx, posy)
                    self.insert(char, posx - 1, posy)
                    self.pos = (posx - 1, posy)
            if direction == 'right':
                if self.grid[posy][posx + 1] != '|':
                    self.insert(' ', posx, posy)
                    self.insert(char, posx + 1, posy)
                    self.pos = (posx + 1, posy)
            count += 1
    def getpos(self, char):
        poslist = []
        for y, i in enumerate(self.grid):
            for x, j in enumerate(i):
                if j == char:
                    poslist.append((x, y))
        return poslist
class Chess(Array):
    def __init__(self):
        row = list(''.join(['.' for i in range(8)]))
        board = [row for i in range(8)]
        super().__init__(board=board)
    def reload(self):
        p = ''
        nums = [i + 1 for i in range(8)]
        nums.reverse()
        for x, i in enumerate(self.grid):
            i = [f'{z} ' for z in i]
            p += f'{nums[x]}  {"".join(i)}n'
        add = [i + ' ' for i in list('ABCDEFG')]
        add.append('H')
        p += '   ' + ''.join(add) + 'n'
        print(p)
    def move(self, move:str):
        move = move.split(' ')
    def placepiece(self, piece, pos):
        pos = list(pos)
        ykey = [i for i in range(8)]
        ykey.reverse()
        x = [x for x, i in enumerate('ABCDEF') if i == pos[0]][0]
        y = ykey[int(pos[1]) - 1]
        x = int(x)
        return x, y
board = Chess()
x, y = board.placepiece(Pieces.White_pawn, 'E4')
board.grid[y][x] = Pieces.White_pawn
print(board.grid)
board.reload()

I expected to get a white pawn character at E4 on the array, but it filled up the entire file like this. Could someone help me with this? I have used 2D arrays in many other projects before, but never encountered this issue. I am happy to elaborate further on anything you need me to.

Asked By: Mark Wilson

||

Answers:

The issue is with the Array constructor. In the grid list, you are appending a list called row for each row of the chess board. However, instead of creating a new list for each row, you are appending the same row list over and over again. As a result, when you modify a cell in one row, it is being modified in all rows.

To fix this, you need to create a new list for each row. You can do this by moving the row initialization inside the loop that creates the rows:

grid = [' ' + '_' * self.x]
for _ in range(y):
    row = ['|']
    for _ in range(x):
        row.append(' ')
    row.append('|')
    grid.append(row)
    row = []  # create a new list for the next row
grid.append(' ' + '‾' * self.x)

With this change, your placepiece method should work correctly and place the pawn at the desired location.

Answered By: Lucián Zeman

The problem is in

class Chess(Array):
    def __init__(self):
        row = list(''.join(['.' for i in range(8)]))
        board = [row for i in range(8)]
        super().__init__(board=board)

You are creating a single list and referencing it multiple times in board.

Change to: board = [row.copy() for i in range(8)]

Answered By: Sweet Sheep
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.