MegaNoobyYT
MegaNoobyYT

Reputation: 23

Chess with PyGame: TypeError: unhashable type: 'list'

I'm trying to make a chess game, I'm watching a tutorial of 2021 using Python 3.9. I'm using 3.10 and maybe thats the reason thats not working. Anyways, let me show you the code:

import pygame as p
import Engine



WIDTH = HEIGHT = 512
DIMENSION = 8 # Las dimensiones del tablero son 8x8
SQ_SIZE = HEIGHT // DIMENSION
MAX_FPS = 15 # Para las animaciones
IMAGES = {}

def loadImages():
    pieces = ["bR", "bN", "bB", "bQ", "bK", "wR", "wN", "wB", "wQ", "wK"]
    for piece in pieces:
        IMAGES[piece] = p.transform.scale(p.image.load("images/" + piece + ".png"), (SQ_SIZE, SQ_SIZE))
    # Nota: Podemos acceder a una imagen diciendo "IMAGES[pieza]"


def main():
    p.init()
    screen = p.display.set_mode((WIDTH, HEIGHT))
    clock = p.time.Clock()
    screen.fill(p.Color("white"))
    gs = Engine.GameState()
    print(gs.board)
    loadImages() # Solo hazlo una vez, antes del loop
    running = True
    while running:
        for e in p.event.get():
            if e.type == p.QUIT:
                running = False
        drawGameState(screen, gs)
        clock.tick(MAX_FPS)
        p.display.flip()

def drawGameState(screen, gs):
    drawBoard(screen) # Dibuja los cuadrados del tablero
    # Pon que se puedan marcar algunas piezas (despues)
    drawPieces(screen, gs.board) # Dibuja las piezas encima de los cuadrados

def drawBoard(screen):
    colors = [p.Color("#f0d9b5"), p.Color("#b58863")]
    for r in range(DIMENSION):
        for c in range(DIMENSION):
            color = colors[((r+c) % 2)]
            p.draw.rect(screen, color, p.Rect(c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE))

def drawPieces(screen, board):
    for r in range(DIMENSION):
        for c in range(DIMENSION):
            piece = board[[r][c]]
            if piece != "--": # No es un cuadrado vacío
                screen.blit(IMAGES[piece], p.Rect(c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE))


if __name__ == "__main__":
    main()

Thats the main file, and here's the engine file:

class GameState():
    def __init__(self):
        # El tablero es una lista 2D de 8x8, cada elemento tiene 2 caracteres
        # El primero caracter representa el color, ya sea "w" para blanco o "b" para negro
        # El segundo caracter representra la figura ya sea "R" para torre, "N" para caballo, "B" para alfil, "Q" para reyna, "K" para rey y "P" para peon
        # "--" Representa un espacio vacio
        self.board = [
            ["bR", "bN", "bB", "bQ", "bK", "bB", "bN", "bR"],
            ["bP", "bP", "bP", "bP", "bP", "bP"," bP", "bP"],
            ["--", "--", "--", "--", "--", "--", "--", "--"],
            ["--", "--", "--", "--", "--", "--", "--", "--"],
            ["--", "--", "--", "--", "--", "--", "--", "--"],
            ["--", "--", "--", "--", "--", "--", "--", "--"],
            ["wP", "wP", "wP", "wP", "wP", "wP"," wP", "wP"],
            ["wR", "wN", "wB", "wQ", "wK", "wB", "wN", "wR"]]
        self.whiteToMove = True
        self.moveLog = []

The error is on line 54:

screen.blit(IMAGES[piece], p.Rect(c*SQ_SIZE, r*SQ_SIZE, SQ_SIZE, SQ_SIZE))

TypeError: unhashable type: 'list'

The code is exactly the same as in the tutorial. Sorry if I don't understand many things, I'm relatively new in Python.

Upvotes: 0

Views: 382

Answers (1)

Bao Huynh
Bao Huynh

Reputation: 1054

The error message comes down to that you were using piece, which is a List, to index the IMAGES dictionary, in the line IMAGES[piece] = .... Unhashasble mutable data type like "List" can't be used as a dictionary key, so Python errors out.

The deeper bug where the error message stems from is in your drawPieces function, where you are using board[[r][c]], which is wrong. Fix it by changing to piece = board[r][c]. When doing double indexing, you do not need to wrap in another square bracket (In fact, it is logically wrong to do that). Kindly refer to this article for more info on how to index a 2d Array (since your board variable is a 2d array)

The reason why board[[r][c]] is wrong is because:

  1. When indexing a list, inside each square bracket pair can only be ONE THING (one value)
  2. Inside the first bracket pair is [r][c]
  3. Python will try to evaluate [r][c] to one single value. So Python will read it as "The list [r] (list of one element r) at index c". For example, when r = 0 and c = 0 --> [0][0] --> is going to be equivalent to
list_of_one_elem = [0]
value_at_index_0 = list_of_one_elem[0] # --> value = [0][0] = 0

Therefore, eventually [r][c], if not index out of range, will returns an Integer

  1. After [r][c] -> [0][0] -> 0, Python evaluation will become board[[r][c]] --> board[0]
  2. piece = board[0] is a LIST, because the 0th index of variable board is the list ["bR", "bN", "bB", "bQ", "bK", "bB", "bN", "bR"]
  3. Then you try to IMAGES[piece]. IMAGES is a dictionary, so IMAGES[piece] means you were trying to use piece as a key to this IMAGES dictionary. However, list is not hashable, thus can't be used as a dictionary key, so Python errors out. The rule is only immutable data types can be used as dictionary keys, like string, tuple, integer, etc.

Case in point, when doing multiple indexing, just use board[1][2][3], no need to wrap the indexes in another big bracket pair (unless you have very specific special logic)

Upvotes: 2

Related Questions