I am attempting to code a FEN number calculator based on a board:
boardPeices = ['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',
]
and have gotten pretty far, to where I have 8 stings, each with a row of the FEN number. Currently, the below code prints this: rnbqkbnr/pppppppp/11111111/11111111/11111111/11111111/PPPPPPPP/RNBQKBNR
print(f'{fenRow1}/{fenRow2}/{fenRow3}/{fenRow4}/{fenRow5}/{fenRow6}/{fenRow7}/{fenRow8}')
The problem is, the FEN number's ones should be concentrated into 8's, as there are 8 numbers next to each other. Due to everything being in strings, I cannot figure out how to add the 8 numbers together, in a way that a different position would still work, where the numbers are separated (ie, after e4)
You can use itertools.groupby:
from itertools import groupby
s = 'rnbqkbnr/pppppppp/11111111/11111111/11111111/11111111/PPPPPPPP/RNBQKBNR'
out = ''.join([x for k, g in groupby(s, lambda x: x=='1')
for x in ([str(len(list(g)))] if k else list(g))])
Output:
'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR'
Example on another input (s = 'rnbqkbnr/ppp1pppp/111p1111/11111111/11111111/11111111/PPPPPPPP/RNBQKBNR'):
'rnbqkbnr/ppp1pppp/3p4/8/8/8/PPPPPPPP/RNBQKBNR'
Use short regex substitution:
import re
s = 'rnbqkbnr/pppppppp/11111111/11111111/11111111/11111111/PPPPPPPP/RNBQKBNR'
new_s = re.sub(r'\d{2,}', lambda m: str(len(m.group())), s)
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR
Related
I have a variable, representing a chessboard filled with random chess pieces. The variable consists of a list of 8 lists,each containing 8 positions filled with either " " (empty position) or a specific chess piece (e.g. "♞"):
chessboard = [
[' ',' ',' ',' ',' ',' ',' ',' '],
[' ',' ',' ',' ',' ',' ',' ',' '],
[' ',' ',' ',' ',' ','♞','♞',' '],
[' ',' ',' ',' ',' ',' ',' ',' '],
[' ',' ',' ',' ',' ',' ',' ',' '],
[' ',' ','♔',' ',' ',' ',' ',' '],
[' ',' ',' ',' ',' ',' ',' ',' '],
[' ',' ',' ',' ',' ',' ',' ',' ']
]
I would like to collect the information of each individual piece in a list:
pieces = []
for row in chessboard:
for piece in row:
if piece != " ":
pieces.append((piece, row.index(piece), chessboard.index(row)))
The above for loop ALMOST works. It has one problem. If there are multiple identical pieces in the same row, it adds the coordinates of the first iterated piece:
[('♞', 5, 2), ('♞', 5, 2), ('♔', 2, 5)]
The second knight should be in position 6,2. Can anybody suggest a workaround?
Using a list comprehension:
out = [(item, j, i) for i,row in enumerate(chessboard)
for j,item in enumerate(row) if item != ' ']
or numpy.where:
import numpy as np
a = np.array(chessboard)
i,j = np.where(a!=' ')
out = list(zip(a[i,j], j, i))
output:
[('♞', 5, 2), ('♞', 6, 2), ('♔', 2, 5)]
enumerate the rows and columns.
pieces = []
for i, row in enumerate(chessboard):
for j, piece in enumerate(row):
if piece != " ":
pieces.append((piece, i, j))
Loop over enumerate(row) and enumerate(row), and if the cell isn't ' ' then add the indices to your list. This is also more efficient, as your solution loops across each row multiple times - once to get across the row, and once each time it wants to find the index of a piece.
There are already some good answers to this question, but I find that numpy may be a good choice for this question:
>>> import numpy as np
>>> board = np.array(chessboard)
>>> board
array([[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', '♞', '♞', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', '♔', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']], dtype='<U1')
>>> i, j = (board != ' ').nonzero()
>>> list(zip(board[i, j], j, i))
[('♞', 4, 2), ('♞', 5, 2), ('♔', 2, 5)]
I'm Trying to make a more advanced Tic Tac Toe program with an 'infinite' amount of lines/rows.
But when I try to mutate the list, it changes the whole column instead of just one spot.
size = 4
board = size * [size*[' ']]
board[0][1] = 'x'
#output:
#[[' ', 'x', ' ', ' '],
# [' ', 'x', ' ', ' '],
# [' ', 'x', ' ', ' '],
# [' ', 'x', ' ', ' ']]
How can I fix that?
It occurs because the inner list each row is made of is the same object that gets repeated.
You can change it to
board = [
[' ']*size
for _ in range(size)
]
Or use a double list comprehension
size = 4
board = [
[' ' for _ in range(size)]
for _ in range(size)
]
board[0][1] = 'x'
print(board)
which both produce
[[' ', 'x', ' ', ' '], [' ', ' ', ' ', ' '], [' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ']]
Kudos to #Pynchia for beating me to the answer. Here is my version of code. I think the problem you were having was a result of your method of creating a list of lists.
size = 4
# simple way to create a list of lists
board = [size * [' '] for i in range(4)]
board[0][1] = 'x'
print(board)
Output will be as expected.
For some reason I'm struggling to initialize a numpy.chararray with spaces.
This works:
char_array1 = np.chararray((3, 3))
char_array1[:] = 'a'
char_array1
Output:
chararray([['a', 'a', 'a'],
['a', 'a', 'a'],
['a', 'a', 'a']],
dtype='|S1')
This doesn't:
char_array2 = np.chararray((3, 3))
char_array2[:] = ' '
char_array2
Output:
chararray([['', '', ''],
['', '', ''],
['', '', '']],
dtype='|S1')
What is causing this? I can't see an option to strip the items or something.
In fact char arrays do remove whitespace:
Versus a regular NumPy array of type str or unicode, this class adds
the following functionality:
values automatically have whitespace removed from the end when indexed
comparison operators automatically remove whitespace from the end when
comparing values vectorized string operations are provided as methods
(e.g. endswith) and infix operators (e.g. "+", "*", "%")
So the answer is use a regular array of type str or unicode:
char_array3 = np.empty((3, 3), dtype='str')
char_array3[:] = ' '
char_array3
Output:
array([[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']],
dtype='|S1')
Just create your array with ndarray:
chararray = np.ndarray((3,3), dtype='S1')
chararray[:]=' '
gives:
array([[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']],
dtype='|S1')
Is there a way to count the amount occurrences of a set of string lists?
For example, when I have this list, it counts 7 ' ' blanks.
list = [[' ', ' ', ' ', ' ', ' ', ' ', ' ']]
print(list.count(' '))
Is there a way I can do this same thing but for a set of multiple lists? Like this for example below:
set = [[' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ']]
print(set.count(' '))
When I do it this same way, the output I get is 0 and not the actual count of occurrences.
Solution
This works:
>>> data = [[' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ']]
>>> sum(x.count(' ') for x in data)
21
You need to count in each sub list. I use a generator expression to do this and sum the results from all sub lists.
BTW, don't use set as a variable name. It is a built-in.
Performance
While not that important for many cases, performance can be interesting:
%timeit sum(x.count(' ') for x in data)
1000000 loops, best of 3: 1.28 µs per loop
vs.
%timeit sum(1 for i in chain.from_iterable(data) if i==' ')
100000 loops, best of 3: 4.79 µs per loop
I have a function that draws rectangles:
def drawTbl(l, w):
ln1 = ' '
ln2 = '-'
ln3 = '|'
x = range(l)
print '+', ln2*w, '+'
for i in range(len(x)):
print ln3, ln1*w, ln3
print '+', ln2*w, '+'
It works fine, but I'm attempting to kind of graph this (this is like a pong clone) so that I can place a ball 'O' at the center and use X and Y for collision detection. When I use this function:
def tblData(l, w):
table=[]
for x in range(l):
table.append([])
for y in range(w):
table.append([])
It does seem to append the blank lists, but when I try to use table[x][y], all I receive is an error.
When I return table from tblData, I do get a list of empty lists,
but say (l, w) is (12, 56), so I'm trying to place ball 'O' at the center of the grid (6, 28), simply typing table[6][28] returns an error, so I don't know how I would append 'O' to table[6,28]
So my question is, how can I effectively access list[x][y]?
Instead of creating empty lists you will need to initialize the values in the inner lists to some reasonable value, like a space.
For example:
def tblData(l, w):
table=[]
for x in range(l):
table.append([' '] * w)
return table
Or more concisely:
def tblData(l, w):
return [[' '] * w for x in range(l)]
Note that [' '] * 3 creates the list [' ', ' ', ' '], so [' '] * w is equivalent to
[' ' for x in range(w)].
For example:
>>> import pprint
>>> table = [[' '] * 4 for x in range(5)]
>>> pprint.pprint(table)
[[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ']]
>>> table[3][1] = 'O'
>>> pprint.pprint(table)
[[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', 'O', ' ', ' '],
[' ', ' ', ' ', ' ']]