1

I'm programming chess, but the board isn't updating when I make a move, despite my putting the instruction "pygame.display.flip()".

As far as I can tell, the array I'm using updates the position of the piece, but for some reason this doesn't translate to the screen.

import pygame
import time
import os
import threading
import queue

pygame.init()

BLACK = (255, 0, 0)
WHITE = (255, 255, 255)
screen_width = 800
screen_height = 600
board_top_left_x = screen_width//5
board_top_left_y = screen_height//10
square_size = screen_height//10
screen = pygame.display.set_mode([screen_width, screen_height])
os.environ['SDL_VIDEO_WINDOWS_POS'] = '10, 10'
commands = queue.Queue


class Input(threading.Thread):
    def run(self):
        while True:
            command = input()
            commands.put(command)


class square(pygame.sprite.Sprite):
    def __init__(self, colour):
        super().__init__()
        self.image = pygame.Surface([square_size, square_size])
        self.rect = self.image.get_rect()
        pygame.draw.rect(self.image, colour, [0, 0, square_size, square_size])
        self.colour = colour


def load_image(name):
    f = pygame.image.load(name + ".png")
    return f


def set_up_board(board):
    board[0][0] = "Rw"
    board[1][0] = "Nw"
    board[2][0] = "Bw"
    board[3][0] = "Qw"
    board[4][0] = "Kw"
    board[5][0] = "Bw"
    board[6][0] = "Nw"
    board[7][0] = "Rw"
    board[0][7] = "Rb"
    board[1][7] = "Nb"
    board[2][7] = "Bb"
    board[3][7] = "Qb"
    board[4][7] = "Kb"
    board[5][7] = "Bb"
    board[6][7] = "Nb"
    board[7][7] = "Rb"
    for i in range(8):
        board[i][1] = "Pw"
        board[i][6] = "Pb"
    return board


def draw_board(board, squares):
    squares.draw(screen)
    for row in range(len(board)):
        for col in range(len(board)):
            if board[col][row] != " ":
                i = load_image(board[col][row])
                i = pygame.transform.scale(i, (square_size, square_size))
                i.set_colorkey(WHITE)
                screen.blit(i, [square_size*col + board_top_left_x, square_size*(7-row) + board_top_left_y])
    pygame.display.flip()


def main():
    squares = pygame.sprite.Group()
     col = BLACK
     I = Input()
     I.start()
     for i in range(8):
         for j in range(8):
             if col == BLACK:
                 col = WHITE
             else:
                 col = BLACK
             x = i*square_size + board_top_left_x
             y = j*square_size + board_top_left_y
             s = square(col)
             s.rect.x = x
             s.rect.y = y
             squares.add(s)
         if col == BLACK:
             col = WHITE
         else:
             col = BLACK
     board = []
     for i in range(8):
          a = []
          for j in range(8):
              a.append(' ')
          board.append(a)
     board = set_up_board(board)
     draw_board(board, squares)
     print("What move do you want to make?")
     answered = False
     while not answered:
         try:
             ans = commands.get(False)
             answered = True
         except queue.Empty:
             ans = None
     board[ord(ans[2]) - 97][int(ans[3]) - 1] = board[ord(ans[0]) - 97][int(ans[1]) - 1]
     board[ord(ans[0]) - 97][int(ans[1]) - 1] = " "
     draw_board(board, squares)
     time.sleep(5)


main()

I would expect this to update the screen with the move, so long as it's legal. From my error checking, it executes the second if statement, and gives me the correct p.x and p.y after they have been changed. What have I missed?

[White bishop image][1][Black bishop image][1][Black king image][1][White king image][1][Black knight image][1][White knight image][1][Black pawn image][1][White pawn image][1][Black queen image][1][White queen image][1][Black rook image][1][White rook image][1]

Note: the input move is in the form "coordinates of piece, coordinates of move", e.g: d2d4

Note2: I have also tried this with piece_list instead of board, and the instruction piece_list.draw(screen) instead of the nested for loops. It has given me exactly the same results.

Arkleseisure
  • 416
  • 5
  • 19
  • Hello! Try to write a [minimal, complete and verifiable example](https://stackoverflow.com/help/mcve) in your question. As it is now, we cannot reproduce the error (I guess we are missing a piece class and the piece list?), so it's difficult to help you. – Valentino Dec 30 '18 at 11:55
  • Done. Also included the images I'm using. In the code, these are referred to by their capital first letter (although knight is "N" so as not to confuse with king) followed by the first letter of their colour in lower case. These are all followed by ".png". – Arkleseisure Dec 30 '18 at 13:04

2 Answers2

0

Ok, I had a look. You said:

From my error checking, it executes the second if statement, and gives me the correct p.x and p.y after they have been changed. What have I missed?

But from my checks, this does not happen. Your piece_list is empty. So here:

for p in piece_list:
    if p.x == ord(ans[0]) - 97 and p.y == int(ans[1]) - 1:
        if p.move_is_possible(board, ans, piece_list, squares) is True:

it never enters the ifs statements and board is left unchanged. If you actually edit the board outside that loop between the two calls to draw_board(board, squares), the board is updated correctly.

Also, you have p.move_is_possible(board, ans, piece_list, squares) but I cannot find a definition of this method anywhere in your code. Is it in a separate file? Is it a sprite method defined in pygame? I am not very expert in pygame, but I cannot find any method like that in the documentation.

Valentino
  • 7,291
  • 6
  • 18
  • 34
  • I noticed this after the second edit and have reedited this with the more relevant code. These issues which you have picked up on are addressed in my actual code :). Thank you otherwise though. – Arkleseisure Dec 30 '18 at 15:10
0

You don't have an event loop, and drawing to/updating the screen is not enough (depending on your OS/window manager).

If you want to use pygame, you need to constantly calling pygame.event.get() (or pygame.event.pump(), but just use .get()), otherwise, the window does not internally process events from your OS, such as the event that tells the window to draw its content.

So you'll have to create a loop where you call pygame.event.get().

If you want to still get input from a terminal, take a look at Is there a way that while running pygame, I can also run the console too?

sloth
  • 99,095
  • 21
  • 171
  • 219
  • I have updated the code on the question with the ideas in your link and answer in mind. However it still doesn't work, and tells me that I need to put a queue instead of a bool in the commands.get() function, as I haven't addressed the self?! I thought that the self part of the function is automatically addressed. Also when I tried it with my main code, it still didn't work. Any ideas why? – Arkleseisure Jan 05 '19 at 14:05