0

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.

  • Do note that writing `global arrowKey`, etc, at the module level is completely meaningless. Those statements have no effect whatsoever. If you want to declare the existence of global variables for readability purposes, you'd be better of using type hints. – Brian61354270 Mar 19 '23 at 16:37
  • Get yourself setup with a debugger. You can then step through the code and inspect variable contents. That will let you ***see*** where unexpected things are happening. It's a core skill. – MatBailie Mar 19 '23 at 16:54

2 Answers2

1

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)]

Sweet Sheep
  • 326
  • 1
  • 6
  • There's a good deal of waste throughout fwiw. `list(''.join(['.' for i in range(8)]))` is unnecessary as `['.' for i in range(8)]` is already the list you want, but `['.'] * 8` is even cleaner – Sweet Sheep Mar 19 '23 at 16:54
  • Thank you so much! I made a modification by defining board like this: board = [list(''.join(['.' for i in range(8)])) for i in range(8)]. – Mark Wilson Mar 19 '23 at 16:55
  • Yes, I know. I just modified necessary code for previous projects to make this do what I want, so there is lots of code left over from previous projects. – Mark Wilson Mar 19 '23 at 16:57
  • It will help readers a lot in the future to spend some time cleaning up the gunk before posting. ^^ – Sweet Sheep Mar 19 '23 at 16:59
  • @MarkWilson Please read [mre] – MatBailie Mar 19 '23 at 17:14
0

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.

  • Where would I put this modifacation? And would it look exactly like it did before? – Mark Wilson Mar 19 '23 at 16:44
  • 2
    `row = ['|']` is already creating a new list at the start of each loop, this change is a no-op. But I have the same suspicion, somehow it's using the same row multiple times in the grid, but this isn't where it's happening. – Sweet Sheep Mar 19 '23 at 16:48