I was trying to build a tic-tac-toe programme, however, I want to understand how to have a static board when user inputs "O" or "X" or when I just want to see the board.
Edit: Outputs appear weird in the question, the first one is a wonky board since it has inputs, whereas the 2nd example is clean.
e.g.
theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O',
'mid-L': 'X', 'mid-M': 'X', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': 'X'}
def printBoard(board):
print(board['top-L'] + ' |' + board['top-M'] + ' |' + board['top-R'])
print('-+-+-')
print(board['mid-L'] + ' |' + board['mid-M'] + ' |' + board['mid-R'])
print('-+-+-')
print(board['low-L'] + ' |' + board['low-M'] + ' |' + board['low-R'])
output:
O |O |O
-+-+-
X |X |
-+-+-
| |X
2nd e.g.
theBoard = {'top-L': '', 'top-M': '', 'top-R': '',
'mid-L': '', 'mid-M': '', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': ''}
def printBoard(board):
print(board['top-L'] + ' |' + board['top-M'] + ' |' + board['top-R'])
print('-+-+-')
print(board['mid-L'] + ' |' + board['mid-M'] + ' |' + board['mid-R'])
print('-+-+-')
print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R'])
output:
| |
-+-+-
| |
-+-+-
| |
So is there a way to make it aesthetically pleasing all the time? or I have to use another model?
Further issues:
You can see that in the last line inside def on the 2nd example there's no space in the '|' which i needed to adjust, however on the first 2 '|' I needed to put a space ' |' which I have no idea why.
If you are going to output an extra space next to each vertical line, your horizontal lines need to account for that. I would actually add a blank space on both sides of the marker.
theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O',
'mid-L': 'X', 'mid-M': 'X', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': 'X'}
def printBoard(board):
print(' {} | {} | {} '.format(board['top-L'], board['top-M'], board['top-R']))
print('---+---+---')
print(' {} | {} | {} '.format(board['mid-L'], board['mid-M'], board['mid-R']))
print('---+---+---')
print(' {} | {} | {} '.format(board['low-L'], board['low-M'], board['low-R']))
Then
>>> printBoard(theBoard)
O | O | O
---+---+---
X | X |
---+---+---
| | X
You also need to remember that each element of the board must be a single character, either X, O, or a space.
wrapping each element with extra space seem to help the presentation a bit.
theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O',
'mid-L': 'X', 'mid-M': 'X', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': 'X'}
separator = '+'.join(('---',)*3)
def printBoard(board):
print(' ' + ' | '.join([board['top-L'], board['top-M'], board['top-R']]))
print(separator)
print(' ' + ' | '.join([board['mid-L'], board['mid-M'], board['mid-R']]))
print(separator)
print(' ' + ' | '.join([board['low-L'], board['low-M'], board['low-R']]))
printBoard(theBoard)
I think you have a fundamental design problem here. The data structure:
theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O',
'mid-L': 'X', 'mid-M': 'X', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': 'X'}
is extremely awkward to manipulate, even with Python 3.6 dict ordering and in spite of (or because of) its semantically named keys. The printing problem you're facing seems to be a side effect of this awkward representation that requires "knowing" all of the magic string keys for each square, so it's pretty much impossible to iterate over it by rows and columns or index into it naturally with 0..2 numbers for rows and columns.
While fixing your printing is the topic of the question, I suspect you have other code that might be pretty ungainly elsewhere in your application.
Consider using a data structure like a 2d list to represent the board. Here's how this might work as a very simple sketch (no error handling or win checking has been added, but this design will be more conducive to writing those things than the current approach):
class TTTBoard:
def __init__(self):
self.board = [[None] * 3 for _ in range(3)]
self.sides = "XO"
self.ply = 0
def move(self, row, col):
if not self.board[row][col]:
self.board[row][col] = self.sides[self.ply%2]
self.ply += 1
return True
def __str__(self):
return "\n---+---+---\n".join(" " + " | ".join(x if x else " " for x in row)
for row in self.board)
if __name__ == "__main__":
board = TTTBoard()
moves = [[0, 1], [0, 2], [2, 1], [1, 0], [1, 1]]
for position in moves:
board.move(*position)
print(board, "\n")
Output:
| X |
---+---+---
| |
---+---+---
| |
| X | O
---+---+---
| |
---+---+---
| |
| X | O
---+---+---
| |
---+---+---
| X |
| X | O
---+---+---
O | |
---+---+---
| X |
| X | O
---+---+---
O | X |
---+---+---
| X |
For the sake of answering your question and for comparison, you could "gather" the board in your original representation into a 2d list, then use the same nested join as above:
theBoard = {'top-L': 'O', 'top-M': 'O', 'top-R': 'O',
'mid-L': 'X', 'mid-M': 'X', 'mid-R': ' ',
'low-L': ' ', 'low-M': ' ', 'low-R': 'X'}
vals = list(theBoard.values())
board = [[vals[i+j*3] for i in range(3)] for j in range(3)]
print("\n---+---+---\n".join(" " + " | ".join(row) for row in board))
This works in Python 3.6+, but having to do this transformation, or indexing into the dictionary again and again by name for each square is less appealing than choosing a usable data structure from the start.
I am converting code to write a function from a different data type.
The original code was:
note_inf_track = np.array([(n.note, n.onset/div, n.duration/div, n.velocity, n.channel, track_nr)
for n in m.tracks[track_nr].notes],
dtype = [('pitch', np.int),
('onset', np.float),
('duration', np.float),
('velocity', np.int),
('channel', np.int),
('track', np.int)])
Now my input data is a 2-dimensional list, I am not working with notes anymore.
for line in lines:
#print("b");
element = [];
for x in line.split(','):
element.append(x.strip('\r\n'));
elements.append(element);
note_inf_track = np.array([(round((round(np.asarray(elements[2], dtype="float")))), (round(np.asarray(elements[0], dtype="float"))),(round(np.asarray(elements[:][1], dtype="float"))))],
dtype = [('pitch', np.int),
('onset', np.float),
('duration', np.float)])
I am struggling to add the columns at once.
elements[2] seems to give me the row instead of the column. I can't seem to replace the for loop. Maybe my syntax is all off, I am used to java and c++, fairly new to Python.
--Update--
Based on Tarun Gaba's answer, I tried this:
note_inf_track = np.array([((round(el[2])), float(el[0]),float(el[1])) for el in elements],
dtype = [('pitch', np.int)
('onset', np.float),
('duration', np.float)]);
Gives me an error:
note_inf_track = np.array([((round(el[2])), float(el[0]),float(el[1])) for el in elements],
TypeError: a float is required
Here is the output of print(elements):
[['0.066667', ' 0.200000', ' 50.180000', ' 0.000644'], ['0.266667', ' 0.266667', ' 59.180000', ' 0.006583'], ['0.550000', ' 0.366667', ' 59.180000', ' 0.002129'], ['0.933333', ' 0.350000', ' 59.180000', ' 0.005972'], ['1.316667', ' 0.050000', ' 59.180000', ' 0.010053'], ['1.366667', ' 0.166667', ' 61.180000', ' 0.008109'], ['1.550000', ' 0.233333', ' 61.180000', ' 0.009170'], ['1.783333', ' 0.416667', ' 63.180000', ' 0.023811'], ['2.250000', ' 0.166667', ' 63.180000', ' 0.016253'], ['2.416667', ' 0.850000', ' 64.180000', ' 0.019314'], ['3.300000', ' 0.116667', ' 64.180000', ' 0.018684'], ['3.433333', ' 0.133333', ' 64.180000', ' 0.016786'], ['3.583333', ' 0.333333', ' 63.180000', ' 0.008623'], ['4.816667', ' 0.383333', ' 63.180000', ' 0.036858'], ['5.200000', ' 0.166667', ' 61.180000', ' 0.006060'], ['5.366667', ' 0.366667', ' 63.180000', ' 0.010417'], ['5.783333', ' 0.333333', ' 63.180000', ' 0.008371'], ['6.116667', ' 0.383333', ' 64.180000', ' 0.007488'], ['6.533333', ' 0.233333', ' 64.180000', ' 0.014582'], ['6.766667', ' 0.333333', ' 63.180000', ' 0.004457'], ['7.533333', ' 0.516667', ' 61.180000', ' 0.004700'], ['8.050000', ' 0.316667', ' 63.180000', ' 0.006959'], ['8.366667', ' 0.300000', ' 64.180000', ' 0.013522'], ['8.666667', ' 0.166667', ' 63.180000', ' 0.008083'], ['8.833333', ' 0.150000', ' 64.180000', ' 0.010620'], ['8.983333', ' 0.250000', ' 63.180000', ' 0.004493'], ['9.233333', ' 0.116667', ' 64.180000', ' 0.012834'], ['9.350000', ' 0.333333', ' 63.180000', ' 0.005321'], ['9.716667', ' 0.300000', ' 64.180000', ' 0.006902'], ['10.033333', ' 0.183333', ' 63.180000', ' 0.002515'], ['10.216667', ' 0.133333', ' 62.180000', ' 0.005928'], ['10.350000', ' 0.600000', ' 63.180000', ' 0.004920'], ['10.950000', ' 0.133333', ' 64.180000', ' 0.006754'], ['11.083333', ' 0.116667', ' 63.180000', ' 0.003831'], ['11.200000', ' 0.316667', ' 62.180000', ' 0.002493']]
elements is a list of lists here.
To access 3rd column(as what you seem to be trying by elements[2]), you need to do something like this:
elements = [[1,2,3], \
[4,5,6], \
[7, 8, 9]]
column = [i[2] for i in elements]
print column
#[3,6,9]
For your case, It should be something on the lines of:
np.array([el[2] for el in elements], [float(el[0]) for el in elements], [float(el[1])) for el in elements], dtype= .....
The problem is that your data is read as list of strings.
Modify your code from:
element.append(x.strip('\r\n'));
To:
element.append(float(x.strip('\r\n')));
To have your data as floats. You could also use round(float(...)) if you need rounded data.
Then put the data into a numpy array:
>>> import numpy as np
>>> data = np.array(elements)
And access to the columns as data[:, column_idx], e.g. for column 3:
>>> data[:, 2]
I passed an argument to a python script like -b bench. The bench is created like this:
bench_dir = '~/myFD/'
bench_bin = bench_dir + 'src/bin/Assembler'
bench_inp1 = bench_dir + 'input/in.fa'
bench_out1 = bench_dir + 'output/data.scratch'
bench= LiveProcess()
bench.executable = bench_bin
bench.cwd = bench_dir
bench.cmd = [bench.executable] + ['-s', bench_out1, '<', bench_inp1]
The bench.cmd should looks like:
~/myFD/src/bin/Assembler -s ~/myFD/output/data.scratch < ~/myFD/input/in.fa
to do that, I use print bench.cmd but it doesn't show the above statment correctly. Instead it shows:
['~/myFD/src/bin/Assembler', '-s', '~/myFD/output/data.scratch', ' < ', '~/myFD/input/in.fa']
how can I fix that?
Try: print ' '.join(bench.cmd). This joins the list and uses a space as delimiter
You could do ' '.join(bench.cmd).
case for join: ' '.join(bench.cmd)
Are you looking for this,
>>> mylist = ['~/myFD/src/bin/Assembler', '-s', '~/myFD/output/data.scratch', ' < ', '~/myFD/input/in.fa']
>>> " ".join(mylist)
'~/myFD/src/bin/Assembler -s ~/myFD/output/data.scratch < ~/myFD/input/in.fa'
or just concatenate your strings
bench.cmd = bench.executable + ' -s ' + bench_out1 + ' < ' + bench_inp1