--- title: chess.com api and the continuing search for en passant checkmate date: 2022-11-08 tags: - chess - python draft: false --- Last time we worked out how to get info for all the games played by titled players in a particular month. Today, we have three objectives: - Parse this info for the pgn (portable game notation) of each game. - Write these to a file so we dont have to spend forever downloading them everytime we run the script. - Devise a way to convert this pgn to a more convenient pythonic format so we can analyse it later. First of all, I wrote a little function to get the pgn from the games we downloaded. I added this KeyError exception, but if I'm honest I'm not sure why I was getting this error. Maybe, chess.com doesn't store pgn for all games? I don't know. ```python def get_pgns(games): pgns = [] for game in games: try: pgn = game['pgn'] pgns.append(pgn) except KeyError: print('key error um') return pgns ``` Now we have this list of pgns, the next goal is to write them to a file so we theoretically only have to run the stuff from last post once. All the analysis we do on the games can then just be done on the files we save without any talking to the internet required. ```python def write_pgns(pgns): with open(month.replace('/','_')+'.csv', 'w') as f: for pgn in pgns: f.write(pgn) ``` Now a pgn looks something like this if it's just printed as a string: ![image alt text](/image/pgn.webp) It contains lots of very useful info but for our purposes of finding en passant checkmates, we would ideally just have a list of each move looking something like this: ```python moves = [ 'e4', 'e5', 'Bc4', 'Nc6', 'Qh5', 'Nf6', 'Qxf7#'] ``` We don't need the headers, we don't need the result, and we don't really need the move numbers (these can be deduced from the list indexes). So the challenge is how to convert the pgn to a list; this is the slightly janky solution I came up wtih. ```python def get_move_list(pgn): x = pgn.split() moves = [] for item in x: # start fresh list at move 1 - effectively skipping the headers from the list if item == '1.': moves = [] moves.append(item) # gets rid of clock bits and bobs elif item[0] == '{' or item[-1] == '}': pass else: moves.append(item) #remove even indexes from list #this gets rid of move numbers and the result of the game del moves[::2] return moves ``` I don't doubt it could be done more elegantly but it works I guess. Next time, we'll deal with working out what a list containing an en passant checkmate would look like.