Outputting tictactoe board - python

I'm trying to print my tictactoe board so it looks like
| |
-+-+-
| |
-+-+-
| |
This is my code:
def __str__(self):
result = ""
for i in range(self.nrows):
for j in range(self.ncols):
cell = str(self.gameboard[i][j])
result += cell + "|"
result += "\n"
result += "-+"
result += '\n'
return result
The result looks like
| | |
-+
| | |
-+
| | |
-+
How should I change the code so it looks like the first board? self.nrows is the number of rows, self.ncols is the number of columns, and self.gameboard is the 2d array.

That's not the most pythonic way, and you probably should diverge the code into some functions, but it's working:
def __str__(self):
result = ""
for i in range(self.nrows):
for j in range(self.ncols-1):
cell = str(self.gameboard[i][j])
result += cell + "|"
result += "\n"
if i == self.nrows - 1:
break # added the last line, which is just |
for j in range(self.ncols-1):
result += "-+"
result += '-'
result += '\n'
return result
Output for self.nrows = self.ncols = 3 and self.gameboard[i][j] = ' ' for each i,j:
| |
-+-+-
| |
-+-+-
| |

You need to change the row result += "-+" to result += "-+" * self.ncols + "-". Reason is that you print "-+" symbol only once, but need to do that as many time as your number of columns. Also, in the end you need to add one more "-" symbol to make it look symmetric. In the end just remove the last row that have 2*ncols+2 symbols.
The complete code would be:
def __str__(self):
result = ""
for i in range(self.nrows):
for j in range(self.ncols):
cell = str(self.gameboard[i][j])
result += cell + "|"
result += "\n"
result += "-+" * self.ncols + "-"
result += '\n'
# Remove the last row
result = result[:-2*ncols-2]
result += "\n"
return result

Related

B-ship game follow up 2: AI and User IDK how to do alternating turns

From this
I have been making a b-ship game but I have run into a problem. It is 3x3, so it's a scaled down version of the actual game. We're using one ship for now.
I currently have the user hitting the AI section done, but how can i make it switch to the Ai's turn after one hit?
The AI, when it is his turn, knows that the user has part of a ship at [4] and that will stay that way for now. then He tries to hit [7], but if that doesn't work, try [1], or if that doesn't work, try [5]. And How can I do this for any edge??
import random
def drawboard(hitboard,hitboard2):
print(' Opponent\'s Your')
print(' Ships Ships')
print('| | | | | | | |')
print('| ' + hitboard[7] + ' | ' + hitboard[8] + ' | ' + hitboard[9] + ' | | ' + hitboard2[7] + ' | ' + hitboard2[8] + ' | ' + hitboard2[9] + ' |')
print('| | | | | | | |')
print('------------- -------------')
print('| | | | | | | |')
print('| ' + hitboard[4] + ' | ' + hitboard[5] + ' | ' + hitboard[6] + ' | | ' + hitboard2[4] + ' | ' + hitboard2[5] + ' | ' + hitboard2[6] + ' |')
print('| | | | | | | |')
print('------------- -------------')
print('| | | | | | | |')
print('| ' + hitboard[1] + ' | ' + hitboard[2] + ' | ' + hitboard[3] + ' | | ' + hitboard2[1] + ' | ' + hitboard2[2] + ' | ' + hitboard2[4] + ' |')
print('| | | | | | | |')
def aiships(hitboard,spot_hit,shipspots,hitboard2):
if spot_hit in shipspots:
hitboard[1] = 'x'
else:
hitboard[7] = 'o'
drawboard(hitboard,hitboard2)
def playerships(hitboard,hitboard2, spot_hit, usershipspots):
hitboard2[7] = 'x'
print("\nComputer's turn.\n")
spot_hit = random.choice(usershipspots)
hitboard2[spot_hit] = 'x'
if spot_hit not in usershipspots:
hitboard2[spot_hit] = 'o'
drawboard(hitboard,hitboard2)
def main():
possiblespots = [[1,2],[2,3],[4,5],[5,6],[7,8],[8,9],[1,4],[4,7],[2,5],[5,8],[3,6],[6,9]]
shipspots = random.choice(possiblespots)
userspots = [[4,7],[4,1],[4,5]]
usershipspots = random.choice(userspots)
gameisplaying = True
ai_spots = [4, 7, 1, 5]
ai_index = 0
while gameisplaying:
hitboard = [' ' for i in range(10)]
hitboard2 = [' ' for i in range(10)]
hitboard2[usershipspots[0]] = 's'
hitboard2[usershipspots[1]] = 's'
userready = input('Place your ships. Type done when you finished placing it.')
while not userready == 'done':
userready = input('Type done when you locate your ship. ')
spot_hit = input('Where\'s the hit?: 1-9 ')
while not (spot_hit in '1 2 3 4 5 6 7 8 9'.split()):
spot_hit = input ('Please tell me where the hit is: 1-9 ')
spot_hit = int(spot_hit)
aiships(hitboard, spot_hit, shipspots, hitboard2)
playerships(hitboard, hitboard2, ai_spots[ai_index], shipspots)
ai_index += 1
main()
But wait, there's more! (billy mays reference)
No matter what number I put in, there will always be an O in the 7 space. Unless I put in the ship coordinates of the playerships (which is quite odd) which will create an X in the 1 space. Also there will always be an 's' in the 3 space on the 'your ships' board. (using numpad for numbers)
So between the two current statements
aiships(hitboard,spot_hit,shipspots,hitboard2)
playerships(hitboard, hitboard2,spot_hit,shipspots)
you need to recompute spot_hit so it's 4 the first time, then 7, then 1, then 5 (we'll worry about "any hedge" in some other future Q, OK?-).
For the purpose, it's simplest to initialize, just before the while:
ai_spots = [4, 7, 1, 5]
ai_index = 0
and then transform those two statements into:
aiships(hitboard, spot_hit, shipspots, hitboard2)
playerships(hitboard, hitboard2, ai_spots[ai_index], shipspots)
ai_index += 1
I hope it's clear how it works here. BTW, a side note, the randomly different order of arguments in the two functions is confusing to no good purpose -- reorder things so that they're the same in both cases!
For the "all hedges" presumably you need a longer list for ai_spots and the ability to increment ai_index by more than one if an attempt was not successful -- which in turn requires playerships to give you a boolean return telling you if the attempt was successful or not, so you can use it to determine how much to change ai_index by.
However that's very premature as you still have many bigger bugs to think about right now. For example, consider the snippet:
spot_hit = random.choice(usershipspots)
if spot_hit in usershipspots:
random.choice always returns one of the items in its argument -- so the check of whether its return value is indeed one of those items is completely redundant -- it will always be True and the body of the if clause will always execute.
No doubt you want to remove that recomputation of spot_hit as a random choice and accept the argument you're passed instead!
The if can remain of course and at the end of the function you can return spot_hit in usershipspots which is exactly the boolean telling you if the hit was successful or not.

Issues with For loops inside of Functions in Python 3.3

Okay, so I'm working on writing a tic tac toe game, and have run into a pretty bad error that I can't seem to solve. I have created a function that will have the computer block the player if the player is about to win, however, after if successfully blocks once, it doesn't trigger anymore even if the conditions are satisfied. The code for the function is:
def block():
for t in range(0, 9, 3):
if slot[t] == user_team and slot[t+1] == user_team and (slot[t+2] \
!= user_team) and (slot[t+2] != computer_team):
slot[int(t+2)] = computer_team
return
elif slot[t+1] == user_team and slot[t+2] == user_team and (slot[t] \
!= user_team) and (slot[t] != computer_team):
slot[int(t)] = computer_team
return
elif slot[t] == user_team and slot[t+2] == user_team and (slot[t+1] \
!= user_team) and (slot[t+1] != computer_team):
slot[int(t+1)] = computer_team
return
for t in range(3):
if slot[t] == user_team and slot[t+3] == user_team and (slot[t + 6] \
!= user_team) and (slot[t+6] != computer_team):
slot[int(t+6)] = computer_team
return
elif slot[t+3] == user_team and slot[t+6] == user_team and (slot[t] \
!= user_team) and (slot[t] != computer_team):
slot[int(t)] = computer_team
return
elif slot[t] == user_team and slot[t+6] == user_team and (slot[t+3] \
!= user_team) and (slot[t+3] != computer_team):
slot[int(t+3)] = computer_team
Also, user_team and computer_team lead back to whether that player is X or O, and the slot[int()] = computer_team is used to place the move on the board.
And below is where the function is called (just in case I messed up here.):
else:
draw_board()
'''win()'''
block()
cmove()
turn = "user"
if end_game() == True:
computer_win += 1
draw_board()
print ("The computer has won! But... We already knew that would happen. (:")
playing = False
elif end_game() == "Tie":
tie_win += 1
draw_board()
print ("The game is a tie. You're going to have to try harder " \
+ "\n" + "if you wish to beat the computer!" + "\n")
playing = False
else:
pass
If any of you could tell me where I went wrong, then that would make my day. c:
Board (Prints are indented, it just doesn't want to here.)
def draw_board():
'''Opted to use lists so that the numbers can be replaced with either
X or O later on and so that testing whether the game is over is simpler'''
print (" " + str(slot[0]) + " | " + str(slot[1]) + " | " + str(slot[2]))
print ("-----------")
print (" " + str(slot[3]) + " | " + str(slot[4]) + " | " + str(slot[5]))
print ("-----------")
print (" " + str(slot[6]) + " | " + str(slot[7]) + " | " + str(slot[8]))
print ("\n")
New ERRROR:
This is my board after I put in move 4
X | O | X
O | 4 | 5
X | 7 | X
The computer's board after it's move 4 (two moves, and replaces an x)
X | O | X
O | 4 | O
O | 7 | X
I believe your problem is in the logic of your block function.
Here is your board:
0 1 2
3 4 5
6 7 8
Walking through the first pair of nested for loops, let's see what your code does:
for t in range(0,9,3):
for y in range(1, 9, 3):
This will give you the follow pairs of t, y: (0,1), (0,4), (0,7), (3,1), (3,4), (3,7), (6,1), (6,4), and (6,7). Right away, I don't think this is what you had intended. From what I can tell, you are trying to check to see if the player has two marks in a row.
This problem is easy to fix - you don't need two for loops. Instead, just use t, t+1, and t+2.
Next, consider a row:
0 1 2
There are three conditions to check for, player has marks at 0 and 1, at 0 and 2, or at 1 and 2. You only check for two of these conditions - 0 and 1, and 1 and 2.
Additionally, the if statement isn't doing what you think it's doing:
if ... and slot[y+1] != user_team and computer_team:
This is equivalent to this:
if ... and (slot[y+1] != user_team) and computer_team:
I assume computer_team is 'x' or 'o', in which case python would use it the same as True in an if statement. What you want is this:
if ... and (slot[y+1] != user_team) and (slot[y+1] != computer_team):
This is also probably why your code would work only once - the next time it goes to evaluate the same row or column it found previously, the if statement will evaluate to True again, and it will set the same space again, which to you looks as if it is doing nothing.
Your code for checking the columns has the same issues. Hopefully the issues I've pointed out will be enough for you to figure out how to fix your code. Good luck!

Variable contains None even after assignment

Here is a function that I wrote:
def conc(i,s,y):
if sheet.cell(i+1,0).value != sheet.cell(2,0).value :
# print s
rtrns = s
# print rtrns
return rtrns
else:
if i==list1[len(list1)-1]:
while i<(sheet.nrows):
# print i
s = s + " " + unicode(sheet.cell(i,y).value).encode('cp1252', 'replace')
i+=1
# print s
rtrns = s
# print rtrns
return rtrns
else:
s = s + " " + unicode(sheet.cell(i+1,y).value).encode('cp1252', 'replace')
#return s
conc(i+1,s,y)
In the above function, when I print the value of rtrns in the first if block, it displays the value that I need.
But when I make a call to the function
c = conc(x,c,2) #where x fetches an integer value as an index from a list
print c
it returns None
The return statement is missing in the else part of your code
else:
s = s + " " + unicode(sheet.cell(i+1,y).value).encode('cp1252', 'replace')
#return s
conc(i+1,s,y)
So, there is one code path, where nothing is returned from your recursive function conc.
Change the code and add a return
else:
s = s + " " + unicode(sheet.cell(i+1,y).value).encode('cp1252', 'replace')
#return s
return conc(i+1,s,y)
A recursive call always returns back to the caller. So, when you recursively call conc, and one of the code path issues a return statement, the call gets back to from where you invoked. Another important thing is, a function without an explicit return has an implicit return with None.
The Following ASCII Art should be self explanatory of what might be going wrong
foo() <------------------------------------------------------------------------
| |
| |
|->def conc(...): |
else: (None)
......... |
conc(i+1,s,y) <-------------------------------------------\ |
return None ----------------------------------------------U--- -|
| |
| |
\----->def conc(...): |
else: (None)
......... |
conc(i+1,s,y) <----------------------\ |
return None ------------------------U--|
| |
| |
| |
\----------->def conc(...): (rtrns)
if ... : |
.......... |
return rtrns----|

Calling functions inside other functions in Python

I'm trying to write a simple program that creates a square grid like this:
+ - - - - + - - - - +
| | |
| | |
| | |
| | |
+ - - - - + - - - - +
| | |
| | |
| | |
| | |
+ - - - - + - - - - +
I want it to take an input x, which defines how many cells are in each row/column. The script is as follows:
def repeat(x, f, *args):
for i in range(x): f(*args)
def topx(x):
print x*top + '+'
def midx(x):
print x*mid + '|'
def block(f,g,*args):
f(*args)
g(*args)
top = str('+ - - - - ')
mid = str('| ')
x = 2
repeat(x,block,topx,repeat,x,4,midx,x)
topx()
I get the following error when I try to run the script:
TypeError: topx() takes exactly 1 argument (4 given)
It's something to do with the arguments in the block function, but can't figure out how to get around it.
Thanks in advance.
Edit:
Thanks for the pointers, I rewrote it slightly as follows and it works nicely. I also changed it to allow you to choose the number of columns and rows independently.
def repeat(x, f, *args):
for i in range(x): f(*args)
def topx(x):
print x*top + '+'
def midx(x):
print x*mid + '|'
def row(x):
topx(x)
repeat(4,midx,x)
top = str('+ - - - - ')
mid = str('| ')
x = 3
y = 4
repeat(y,row,x)
topx(x)
def topx(x):
print x*top + '+'
This takes one argument: x. But when you call it:
def block(f,g,*args):
f(*args) # This is what calls topx
g(*args)
You're passing it *args, which contains [x, 4, midx, x]. And that's four arguments right there.
You should probably reconsider your structure to fix this. Perhaps a class?
def grid(x, space=4):
for i in range(x):
print ("+" + "-"*space)*x + "+"
for j in range(space):
print ("|" + " "*space)*x + "|"
print ("+" + "-"*space)*x + "+"
I think this is not best way. but your script can be easily updated to be more readable and working.
cell_number = 2
top = str('+ - - - - ')
mid = str('| ')
def repeat(cell_number, f, *args):
"""
repeat call of function `f` `call_number` times
"""
for i in range(cell_number):
f(*args)
def topx(cell_number):
"""
draw horizontal edge
"""
print cell_number * top + '+'
def midx(cell_number):
"""
draw middle part with vertical edges
"""
print cell_number * mid + '|'
def block(cell_num):
"""
draw one row of `cell_num` cells
"""
topx(cell_num)
repeat((len(top) - 1)/2, midx, cell_num)
repeat(cell_number, block, cell_number)
topx(cell_number)
def box(width, height, cell=1):
print '+' + ('- ' * width + '+') * cell
for x in range(cell):
for x in range(height):
print '|' + (' ' * width + '|') * cell
print '+' + ('- ' * width + '+') * cell

Card Matching Game on Python

I am current building a simple card matching game in python, with a 5x4 (row*column) grid, in which two players try to match a deck of twenty cards (2,10 of only suit Hearts) * 2.
The problem I am running into is in iterating through the deck, printing the cards out in a grid fashion so it would look like this:
----- ----- ----- -----
- - - - - - - -
4-H 6-H 7-H 8-H
- - - - - - - -
----- ----- ----- -----
The code I currently have is below:
#needed import for shuffle function
from random import shuffle
#class for my deck
class Deck:
#constructor starts off with no cards
def __init__( self ):
self._deck = []
#populate the deck with every combination of suits and values
def Populate( self ):
#Heart, Diamond, Spades, Clubs
for suit in 'HDSC':
#Jack = 11, Queen = 12, King = 13, Ace = 14
for value in range(2, 15):
if value == 11:
value = 'J'
elif value == 12:
value = 'Q'
elif value == 13:
value = 'K'
elif value == 14:
value = 'A'
#add to deck list
self._deck.append(str(value) + '-' + suit)
#populate the deck with only hears hearts and all cards except face cards and aces (2, 3, 4, 5, 6, 7, 8, 9, 10) twice
def gamePop( self ):
suit = 'H'
for x in range(2):
for value in range(2, 11):
self._deck.append(str(value) + '-' + suit)
#shuffle the deck with the random import
def Shuffle( self ):
shuffle( self._deck )
#length of the deck
def len( self ):
return len( self._deck )
def stringIt( self ):
#Returns the string representation of a deck
result = ''
for c in self._deck:
result = result + str(c) + '\n'
return result
#class for a single card
class Card:
#constructor for what type of card it is
def __init__( self, value, suit ):
self._value = value
self._suit = suit
self._card = self._value + self._suit
#print the type of card
def Description( self ):
return ( self._card )
#overloaded ==
def __eq__( self, another ):
if ( self._card == another.Description() ):
return True
else:
return False
#main function which plays the game
def main():
#sets player counters to zero,
pOneCount = 0
pTwoCount = 0
#creates the deck to be put on the board
gameDeck = Deck()
gameDeck.gamePop()
gameDeck.Shuffle()
print(gameDeck._deck)
currentCard = 0
for row in range(5):
for card in range(0,4+i):
mystring =
print ('------- ' * 4)
print ('| | ' * 4)
for x in range(4):
print ('| ' +gameDeck._deck[currentCard]+'|'),
currentCard += 1
print ('| | ' * 4)
print ('------- ' * 4)
Edit: I cleared up the code which I've tried.
The current output is this:
------- ------- ------- -------
| | | | | | | |
| 7-H|
| 5-H|
| 7-H|
| 9-H|
| | | | | | | |
------- ------- ------- -------
the problem is in the def main():
def main():
print ('------- ' * 4)
print ('| | ' * 4)
for x in range(4):
print ('| ' +gameDeck._deck[currentCard]+'|'),
currentCard += 1
print ('| | ' * 4)
print ('------- ' * 4)
the * 4 just mean that this:
print ('------- ' * 4)
will become this:
print ('------- ' + '------- ' + '------- ' + '------- ' )
it can also be type as:
print ('------- ------- ------- ------- ' )
so. your problem is here:
for x in range(4):
print ('| ' +gameDeck._deck[currentCard]+'|'),
currentCard += 1
this would print as:
| 7-H|
| 5-H|
| 7-H|
| 9-H|
you need to put it as something like this:
print ('| ' +gameDeck._deck[currentCard]+'|'+'| ' +gameDeck._deck[currentCard+1]+'|'+'| ' +gameDeck._deck[currentCard+2]+'|'+'| ' +gameDeck._deck[currentCard+3]+'|')
so it would print in one line like how you want it:
| 7-H| | 5-H| | 7-H| | 9-H|
here is the code that i clean up a little. if it work like it should, it should work:
def main():
#sets player counters to zero,
pOneCount = 0
pTwoCount = 0
#creates the deck to be put on the board
gameDeck = Deck()
gameDeck.gamePop()
gameDeck.Shuffle()
print(gameDeck._deck)
currentCard = 0
for row in range(5):
for card in range(0,4+i):
print (' ------- ' * 4)
print (' | | ' * 4)
print (' | ' +gameDeck._deck[currentCard]+' | '+' | ' +gameDeck._deck[currentCard+1]+' | '+' | ' +gameDeck._deck[currentCard+2]+' | '+' | ' +gameDeck._deck[currentCard+3]+' | ')
print (' | | ' * 4)
print (' ------- ' * 4)
oh, and like John Y say (copy and paste):
The main function has a dangling mystring =, which is a blatant syntax error
here what i use to test, because the whole code don't work for me, i just tested the print part:
print (' ------- ' * 4)
print (' | | ' * 4)
print (' | ' +"1-H"+' | '+' | ' +"2-H"+' | '+' | ' +"3-H"+' | '+' | ' +"4-H"+' | ')
print (' | | ' * 4)
print (' ------- ' * 4)
that got me:
------- ------- ------- -------
| | | | | | | |
| 1-H | | 2-H | | 3-H | | 4-H |
| | | | | | | |
------- ------- ------- -------
>>>

Categories

Resources