First completed project - short/simple game

This is the place to post any code that you want to share with the community. Only completed scripts should be posted here.

First completed project - short/simple game

Postby ovisam » Sun Dec 22, 2013 10:05 pm

Hi, I wondered if anyone could take a look at a simplified Battleship game I've written. It's my first piece of code so I'd appreciate any advice about how it could be improved - in particular the layout and commenting. As far as I know there are no bugs but I'm likely to be wrong...

Code: Select all
from random import randint

print 'Welcome to Battleship. The object of the game is to locate and destroy the enemy ship. You must correctly guess two co-ordinates occupied by the ship to destroy it. This is a 1-player game with a single enemy ship, and you have 10 turns.'
print

def select_difficulty_level():
    '''makes sure player enters a valid difficulty level'''
    level=raw_input('Please select a difficulty level (easy/hard): ')
    level=level.lower()
    while level not in ('easy', 'hard'):
        print 'Sorry, I don\'t know what that means.\n'
        level=raw_input('Please select a difficulty level (easy/hard): ')
        level=level.lower()
    return level
   
def create_board():
    board=[]
    for x in xrange(8):
        board.append(["O"] * 8)

def print_board(board):
    for row in board:
        print "  ".join(row)
        print

def generate_ship(level):
    '''generates the co-ordinates of the top-left point of the ship''' 
    random_row=randint(0,len(board)-2)
    random_col=randint(0,len(board[0])-3)

    '''creates the rest of the ship for hard mode - ship is 1x2'''
    if level=='hard':
        row_1_1=random_row
        col_1_1=random_col
        row_2_1=row_1_1+1
        col_2_1=col_1_1
        ship_h=[[row_1_1,col_1_1],[row_2_1,col_2_1]]
         
    '''creates the rest of the ship for easy mode - ship is 2x3'''   
    if level=='easy':
        row_1_1=random_row
        col_1_1=random_col         
        row_1_2=row_1_1
        col_1_2=col_1_1+1           
        row_2_1=row_1_1+1
        col_2_1=col_1_1       
        row_2_2=row_1_1+1
        col_2_2=col_1_1+1 
        row_3_1=row_1_1+2
        col_3_1=col_1_1       
        row_3_2=row_1_1+2
        col_3_2=col_1_1+1
        ship_e=[[row_1_1,col_1_1],[row_1_2,col_1_2],[row_2_1,col_2_1],[row_2_2,col_2_2],[row_3_1,col_3_1],[row_3_2,col_3_2]]
 
def correct__guess(guess_row,guess_col):
    '''function called when the player guesses correctly'''
    print "You hit the ship!\n"
    board[guess_row][guess_col]="H "
    if level=='easy':
        ship_e[ship_e.index([guess_row,guess_col])] = "H "
    if level=='hard':
        ship_h[ship_h.index([guess_row,guess_col])] = "H "
    print_board(board)

def incorrect_guess(guess_row,guess_col):
    '''function called when the player guesses incorrectly'''
    if (guess_row < 0 or guess_row>7) or (guess_col<0 or guess_col>7):
        print "You can't fire there, sorry.\n"
    elif board[guess_row][guess_col]=="X ":
        print "You've already fired there...\n"
    else:
        print "You missed my battleship!\n"
        board[guess_row][guess_col] = "X "
    print_board(board)   
     
def check_sunk(ship):
    '''checks if ship has been sunk yet'''
    if ship.count("H ")==2:
            return True
    else:
        return False
               
select_difficulty_level()
print "Let's play!\n"
create_board()
print_board(board)    #ERROR HERE
generate_ship(level)   #ERROR HERE

for turn in xrange(1,11): 
    #if player has used up their 10 turns:
    if turn==10:
        print "You're out of turns! Game over."
        break
else:
    print 'You are on turn '+str(turn+1)
    print
   
    #makes sure player guesses a number:
    while True:
        guess_row=raw_input("Guess row number: ")
        print
        if guess_row.isdigit():
            break           
        print "Hmm, did you type a number? Please try again.\n"
    guess_row=int(guess_row)-1
    while True:
        guess_col= raw_input("Guess column number: ")
        print
        if guess_col.isdigit():
            break
        print "Hmm, did you type a number? Please try again.\n"
    guess_col=int(guess_col)-1
   
    #checks to see if player has guessed correctly:
    if level=='easy':
        if [guess_row,guess_col] in ship_e:
            correct_guess(guess_row,guess_col)
            if check_sunk(ship_e):
                print "Congratulations! You sunk my battleship!\n"
        else:
            incorrect_guess(guess_row,guess_col)
    elif level=='hard':
        if [guess_row,guess_col] in ship_h:
            correct_guess(guess_row,guess_col)
            if check_sunk(ship_h):
                print "Congratulations! You sunk my battleship!\n"
        else:
            incorrect_guess(guess_row,guess_col)

Last edited by ovisam on Tue Dec 24, 2013 6:29 pm, edited 1 time in total.
ovisam
 
Posts: 8
Joined: Sat Dec 21, 2013 12:13 am

Re: First completed project - short/simple game

Postby micseydel » Mon Dec 23, 2013 11:46 pm

The layout could be improved by having no floating code. That is, no code at the global level (unindented) that isn't a function definition. That forces everything to be in nice, modular functions to which you would assign nice names and doc strings. When I read code I tend to ignore comments that aren't doc strings. For example, in your code that gets the difficulty choice, your comment would be better off just being a well-named function definition, perhaps with a doc string (never hurts). Same for creating the board, and then the comment for printing the board is redundant to the function name.

There are some nice idioms in Python too, which you mean by interested. For example you have this code
Code: Select all
while level!='easy' and level!='hard':

but a real Pythonista would write
Code: Select all
while level not in ('easy', 'hard'):


On line 19 where you use the string literal "O " I wondered why the space, and guessed that "O" means "open". A good habit to get into is to not use "magic literals" (people often talk about "magic numbers") which are literals that appear in code without meaningful naming and which you might see elsewhere but can't know if they mean the same thing in different places. The convention is to create a "constant" which you can and often should put in the global namespace, but it will be in ALL_CAPS and you will, by convention, never modify it (some languages have provisions to prevent entirely modifications, Python does not).

As for the space, if it's a display issue, I would simply use two spaces in the string you use with join(). And O, H, and X could all probably be renamed as global constants (OPEN, HIT, and MISS?).

On lines 87 and 91 you have logic to check for easy/hard quite late in your program. All you're doing there is looking at which of the two datastructures you created though, the important logic is the same. You can simplify
Code: Select all
def check_sunk():
    if level=='easy' and ship_e.count("H ")==2:
            print "Congratulations! You sunk my battleship!"
            print
            return True
    elif level=='hard' and ship_h.count("H ")==2:
            print "Congratulations! You sunk my battleship!"
            print
            return True
    else:
        return False

to simply
Code: Select all
def check_sunk(ship):
    if ship.count("H ")==2:
            print "Congratulations! You sunk my battleship!\n"
            return True
    else:
        return False

Simply pass the relevant one in as a function argument. You probably don't need to create both of them when you do anyway, just create the one you're actually going to use.

In your mainloop, you always increment turn. Just loop over the proper values by passing 1 as the first argument to range(). (By the way, a good Python 2 habit is to use xrange() instead of range() for reasons I won't go into here but you can Google.) When you need to detect win/loss, you can do so with Python's else branch of a for loop. I include an example below of what it does
Code: Select all
>>> for x in xrange(5):
   if x == 10:
      break
else:
   print "You don't use break!"

   
You don't use break!
>>> for x in xrange(20):
   if x == 10:
      break
else:
   print "You don't use break!"
Join the #python-forum IRC channel on irc.freenode.net!

Please do not PM members regarding questions which are meant to be discussed publicly. The point of the forum is so that others can benefit from it. We don't want to help you over PMs or emails.
User avatar
micseydel
 
Posts: 1258
Joined: Tue Feb 12, 2013 2:18 am
Location: Mountain View, CA

Re: First completed project - short/simple game

Postby ovisam » Tue Dec 24, 2013 6:53 pm

Hi micseydel,

Thanks for taking the time to have a look! I really appreciate your advice and suggestions. :D I've modified the original post to include the updated version of the programme, but I'm having a few problems (warning - it's not running right now)

As per your suggestion, I put the code for selecting the difficulty choice and creating the board into functions, then call them at the start of the game. For some reason, I get errors saying 'board' and 'level' aren't defined - I don't understand why, because before these functions I call select_difficulty_level which defines the level and I call the create_board function which defines the board.

micseydel wrote:On line 19 where you use the string literal "O " I wondered why the space, and guessed that "O" means "open". A good habit to get into is to not use "magic literals" (people often talk about "magic numbers") which are literals that appear in code without meaningful naming and which you might see elsewhere but can't know if they mean the same thing in different places. The convention is to create a "constant" which you can and often should put in the global namespace, but it will be in ALL_CAPS and you will, by convention, never modify it (some languages have provisions to prevent entirely modifications, Python does not).

As for the space, if it's a display issue, I would simply use two spaces in the string you use with join(). And O, H, and X could all probably be renamed as global constants (OPEN, HIT, and MISS?).


The reason I have the "O", "H" and "X" string literals is so that when I print the board, the player gets a visual representation of the board, something like this to keep track of hits and misses:

Code: Select all
O O O O O
O O H O O
O O O X O
O O O O O
O O O O O


I appreciate that this is confusing for anyone reading the code... Would there be a better way of doing this though? Perhaps I could add a comment explaining what I'm doing.

micseydel wrote:In your mainloop, you always increment turn. Just loop over the proper values by passing 1 as the first argument to range(). (By the way, a good Python 2 habit is to use xrange() instead of range() for reasons I won't go into here but you can Google.) When you need to detect win/loss, you can do so with Python's else branch of a for loop.


I'm a bit confused about how to implement the for/else loop - in my current version of the program, it seems like the "turn" value is increasing by 1 until it hits 10, and then the 'else' part is carried out. When you say increment 'turn', do you mean write turn+=1?

Thanks :)
ovisam
 
Posts: 8
Joined: Sat Dec 21, 2013 12:13 am

Re: First completed project - short/simple game

Postby micseydel » Tue Dec 24, 2013 10:12 pm

We're happy to help! I know people can sometimes be self-conscious about their code, which inhibits improvement, so kudos for posting here.

By the way, it would be better if in the future you left the original version and then posted the updated code, rather than removing the old, which can be a useful reference (especially if the old code worked and the new doesn't :roll: ).

ovisam wrote:As per your suggestion, I put the code for selecting the difficulty choice and creating the board into functions, then call them at the start of the game. For some reason, I get errors saying 'board' and 'level' aren't defined - I don't understand why, because before these functions I call select_difficulty_level which defines the level and I call the create_board function which defines the board.

When you get errors, don't just provide a snippet of them, please provide the entire traceback verbatim. For example, when I run the following code in IDLE,
Code: Select all
def f():
    limited_scope_variable = True

f()
print limited_scope_variable

I get the following traceback
Code: Select all
Traceback (most recent call last):
  File "<pyshell#16>", line 1, in <module>
    print limited_scope_variable
NameError: name 'limited_scope_variable' is not defined

Including this full traceback verbatim and in code tags really helps us to figure out your problem quickly. The problem here is that "limited_scope_variable" is local to the function, so I can't access it from outside the function (here the global scope) without making it available explicitly. This is done so with function parameters and return values, which you can read about in any tutorial on functions. After you take a look at one of those if you're still having trouble feel free to ask any questions you have about that.

As for the spaces at the end of your strings, you don't need them to be in the strings you're using since when you do the formatting with join() you can solve that problem there and then. When you do
Code: Select all
separator.join(sequence)

you create a new string with the separator stick in between each thing in the sequence. Below I show what's going on in your code, more or less.

Code: Select all
>>> board = [['O', 'O', 'O', 'O', 'O'],
 ['O', 'O', 'O', 'O', 'O'],
 ['O', 'O', 'O', 'O', 'O'],
 ['O', 'O', 'O', 'O', 'O'],
 ['O', 'O', 'O', 'O', 'O']]
>>> for row in board:
        print " ".join(row) # separator is a space character
        print

       
O O O O O

O O O O O

O O O O O

O O O O O

O O O O O

>>>
>>> for row in board:
        print "".join(row) # separator is empty string

       
OOOOO
OOOOO
OOOOO
OOOOO
OOOOO

Also, in case this wasn't clear before, you can create constants to represent the values because they're named, but because the variable represents a string when you print it the user gets the intended experience.

ovisam wrote:I'm a bit confused about how to implement the for/else loop - in my current version of the program, it seems like the "turn" value is increasing by 1 until it hits 10, and then the 'else' part is carried out. When you say increment 'turn', do you mean write turn+=1?

The majority of your code is in the for part, the else branch will only contain code you wish to be executed when the loop completes without you using break. And just for some clarity here, the loop
Code: Select all
for x in xrange(10):
    print x

is very much like
Code: Select all
x = 0
while x < 10:
    print x
    x += 1

but in the for loop, you're iterating over a sequence. You literally have a sequence of those numbers and you're going through them
Code: Select all
>>> print list(xrange(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

The else branch of a for-loop gets executed when you run out of things in the list. If you use break, you don't run out, you exit the entire construct (for-else-loop) early. You usually don't want to use the loop variable in the else part by the way; it'll always be the last element (since Python leaks out the variable you name in the for loop rather than it just being in the for loop).

When I say you're incrementing turn, I mean that you're literally adding 1 to turn every time you print it out
Code: Select all
print 'You are on turn '+str(turn+1)

There's no need for this if you loop over the proper values, which you can do by using the optional start value of xrange().
Join the #python-forum IRC channel on irc.freenode.net!

Please do not PM members regarding questions which are meant to be discussed publicly. The point of the forum is so that others can benefit from it. We don't want to help you over PMs or emails.
User avatar
micseydel
 
Posts: 1258
Joined: Tue Feb 12, 2013 2:18 am
Location: Mountain View, CA

Re: First completed project - short/simple game

Postby ovisam » Thu Dec 26, 2013 11:49 pm

Hi!

Thanks again for your advice, I think I've included everything and now have a neat, working version of Battleship :D :

Code: Select all
from random import randint

OPEN='O'
HIT='H'
MISS='X'

print 'Welcome to Battleship! The object of the game is to locate and destroy the enemy ship. You must correctly guess two co-ordinates occupied by the ship to destroy it. This is a 1-player game with a single enemy ship, and you have 10 turns.\n'

def select_difficulty_level():
    '''makes sure player enters a valid difficulty level'''
    level=raw_input('Please select a difficulty level (easy/hard): ')
    level=level.lower()
    while level not in ('easy', 'hard'):
        print 'Sorry, I don\'t know what that means.'
        level=raw_input('Please select a difficulty level (easy/hard): ')
        level=level.lower()
    return level
   
def create_board():
    board=[]
    for x in xrange(8):
        board.append([OPEN] * 8)
    return board

def print_board(board):
    for row in board:
        print "  ".join(row)
    print

def generate_ship(level):
    '''generates the co-ordinates of the top-left point of the ship''' 
    random_row=randint(0,len(board)-2)
    random_col=randint(0,len(board[0])-3)

    '''creates the rest of the ship for hard mode - ship is 1x2'''
    if level=='hard':
        row_1_1=random_row
        col_1_1=random_col
        row_2_1=row_1_1+1
        col_2_1=col_1_1
        ship_h=[[row_1_1,col_1_1],[row_2_1,col_2_1]]
        return ship_h
         
    '''creates the rest of the ship for easy mode - ship is 2x3'''   
    if level=='easy':
        row_1_1=random_row
        col_1_1=random_col         
        row_1_2=row_1_1
        col_1_2=col_1_1+1           
        row_2_1=row_1_1+1
        col_2_1=col_1_1       
        row_2_2=row_1_1+1
        col_2_2=col_1_1+1 
        row_3_1=row_1_1+2
        col_3_1=col_1_1       
        row_3_2=row_1_1+2
        col_3_2=col_1_1+1
        ship_e=[[row_1_1,col_1_1],[row_1_2,col_1_2],[row_2_1,col_2_1],[row_2_2,col_2_2],[row_3_1,col_3_1],[row_3_2,col_3_2]]
        return ship_e
       
def correct_guess(guess_row,guess_col):
    '''function called when the player guesses correctly'''
    print "You hit the ship!\n"
    board[guess_row][guess_col]=HIT
    ship[ship.index([guess_row,guess_col])]=HIT
    print_board(board)

def incorrect_guess(guess_row,guess_col):
    '''function called when the player guesses incorrectly'''
    if (guess_row < 0 or guess_row>7) or (guess_col<0 or guess_col>7):
        print "You can't fire there, sorry.\n"
    elif board[guess_row][guess_col]==MISS:
        print "You've already fired there...\n"
    else:
        print "You missed my battleship!\n"
        board[guess_row][guess_col]=MISS
    print_board(board)   
     
def check_sunk(ship):
    '''checks if ship has been sunk yet'''
    if ship.count(HIT)==2:
            return True
    else:
        return False
               
level=select_difficulty_level()
print
print "Let's play!\n"
board=create_board()
print_board(board)
ship=generate_ship(level)

for turn in xrange(1,11): 
    print 'You are on turn '+str(turn)
    #makes sure player guesses a number:
    while True:
        guess_row=raw_input("Guess row number: ")
        if guess_row.isdigit():
            break           
        print "Hmm, did you type a number? Please try again."
    guess_row=int(guess_row)-1
    while True:
        guess_col= raw_input("Guess column number: ")
        print
        if guess_col.isdigit():
            break
        print "Hmm, did you type a number? Please try again."
    guess_col=int(guess_col)-1
   
    #checks to see if player has guessed correctly:
    if [guess_row,guess_col] in ship:
        correct_guess(guess_row,guess_col)
        if check_sunk(ship):
            print "Congratulations! You sunk my battleship!"
            break
    else:
        incorrect_guess(guess_row,guess_col)

else:
    #if player has used up their 10 turns:
        print "You're out of turns! Game over."


Got a few things I'd like to check:
1. I've replaced 'O' with OPEN etc and put these definitions at the start of the program - is that ok or would it be better practice to put these elsewhere?
2. The game works the way I want it to but I'm a bit concerned about something regarding local and global variables. When the player, say, misses and their guess is replaced by an X on the board, that new definition is local to the incorrect_guess function, right? But when the player guesses correctly and the correct_guess function is called, at the end of the function the new board is printed with the previous misses. Why does it not ignore the misses and just print the original board plus the new hit?

Cheers :D
ovisam
 
Posts: 8
Joined: Sat Dec 21, 2013 12:13 am

Re: First completed project - short/simple game

Postby micseydel » Fri Dec 27, 2013 11:21 pm

Kudos on getting it working and cleaning it up! Global constants tend to be put at the top of the program, so where you have them is good.

ovisam wrote:2. The game works the way I want it to but I'm a bit concerned about something regarding local and global variables. When the player, say, misses and their guess is replaced by an X on the board, that new definition is local to the incorrect_guess function, right? But when the player guesses correctly and the correct_guess function is called, at the end of the function the new board is printed with the previous misses. Why does it not ignore the misses and just print the original board plus the new hit?

The only global variables you should have are constants (constants by convention, technically still variables). The idea is that you should have one nice main() function that is very readable at a high level, that passes around all the information that anything else needs. Soon you'll want to consider object oriented programming if you want to tidy things up further, although OOP is an advanced topic in programming so you should be quite happy with the progress you've made here.

Before giving further advice I'll leave it to you to remove all the global variables you have, since you did quite a good job at this first pass and so you'll probably do quite well at that. I do want to reiterate that you all your code other than global constant declarations should be in functions, including that print at the top of your file. When someone imports your file, there shouldn't be any output or anything.
Join the #python-forum IRC channel on irc.freenode.net!

Please do not PM members regarding questions which are meant to be discussed publicly. The point of the forum is so that others can benefit from it. We don't want to help you over PMs or emails.
User avatar
micseydel
 
Posts: 1258
Joined: Tue Feb 12, 2013 2:18 am
Location: Mountain View, CA

Re: First completed project - short/simple game

Postby ovisam » Sat Dec 28, 2013 12:55 am

How's this?

Code: Select all
from random import randint

OPEN='O'
HIT='H'
MISS='X'

def welcome():
    print 'Welcome to Battleship! The object of the game is to locate and destroy the enemy ship. You must correctly guess two co-ordinates occupied by the ship to destroy it. This is a 1-player game with a single enemy ship, and you have 10 turns.\n'

def select_difficulty_level():
    '''makes sure player enters a valid difficulty level'''
    level=raw_input('Please select a difficulty level (easy/hard): ')
    level=level.lower()
    while level not in ('easy', 'hard'):
        print 'Sorry, I don\'t know what that means.'
        level=raw_input('Please select a difficulty level (easy/hard): ')
        level=level.lower()
    return level
   
def create_board():
    board=[]
    for x in xrange(8):
        board.append([OPEN] * 8)
    return board

def print_board(board):
    for row in board:
        print "  ".join(row)
    print

def generate_ship(level,board):
    '''generates the co-ordinates of the top-left point of the ship''' 
    random_row=randint(0,len(board)-2)
    random_col=randint(0,len(board[0])-3)

    '''creates the rest of the ship for hard mode - ship is 1x2'''
    if level=='hard':
        row_1_1=random_row
        col_1_1=random_col
        row_2_1=row_1_1+1
        col_2_1=col_1_1
        ship_h=[[row_1_1,col_1_1],[row_2_1,col_2_1]]
        return ship_h
         
    '''creates the rest of the ship for easy mode - ship is 2x3'''   
    if level=='easy':
        row_1_1=random_row
        col_1_1=random_col         
        row_1_2=row_1_1
        col_1_2=col_1_1+1           
        row_2_1=row_1_1+1
        col_2_1=col_1_1       
        row_2_2=row_1_1+1
        col_2_2=col_1_1+1 
        row_3_1=row_1_1+2
        col_3_1=col_1_1       
        row_3_2=row_1_1+2
        col_3_2=col_1_1+1
        ship_e=[[row_1_1,col_1_1],[row_1_2,col_1_2],[row_2_1,col_2_1],[row_2_2,col_2_2],[row_3_1,col_3_1],[row_3_2,col_3_2]]
        return ship_e
       
def correct_guess(guess_row,guess_col,board,ship):
    '''function called when the player guesses correctly'''
    print "You hit the ship!\n"
    board[guess_row][guess_col]=HIT
    ship[ship.index([guess_row,guess_col])]=HIT
    print_board(board)

def incorrect_guess(guess_row,guess_col,board):
    '''function called when the player guesses incorrectly'''
    if (guess_row < 0 or guess_row>7) or (guess_col<0 or guess_col>7):
        print "You can't fire there, sorry.\n"
    elif board[guess_row][guess_col]==MISS:
        print "You've already fired there...\n"
    else:
        print "You missed my battleship!\n"
        board[guess_row][guess_col]=MISS
    print_board(board)   
     
def check_sunk(ship):
    '''checks if ship has been sunk yet'''
    if ship.count(HIT)==2:
        return True
    else:
        return False

def main():
    welcome()
    level=select_difficulty_level()
    print
    print "Let's play!\n"
    board=create_board()
    print_board(board)
    ship=generate_ship(level,board)
   
    for turn in xrange(1,11): 
        print 'You are on turn '+str(turn)
        #makes sure player guesses a number:
        while True:
            guess_row=raw_input("Guess row number: ")
            if guess_row.isdigit():
                break           
            print "Hmm, did you type a number? Please try again."
        guess_row=int(guess_row)-1
        while True:
            guess_col= raw_input("Guess column number: ")
            print
            if guess_col.isdigit():
                break
            print "Hmm, did you type a number? Please try again."
        guess_col=int(guess_col)-1
   
        #checks to see if player has guessed correctly:
        if [guess_row,guess_col] in ship:
            correct_guess(guess_row,guess_col,board,ship)
            if check_sunk(ship):
                print "Congratulations! You sunk my battleship!"
                break
        else:
            incorrect_guess(guess_row,guess_col,board)

    else:
        #if player has used up their 10 turns:
        print "You're out of turns! Game over."
                       
main()       
ovisam
 
Posts: 8
Joined: Sat Dec 21, 2013 12:13 am

Re: First completed project - short/simple game

Postby Mekire » Sat Dec 28, 2013 1:18 am

Try not to repeat code. Pull your input checking into its own function.

Something like:
Code: Select all
def get_input(prompt):
    while True:
        guess = raw_input("Guess {} number: ".format(prompt))
        print("")
        if guess.isdigit():
            return int(guess)-1
        print("Hmm, did you type a number? Please try again.")


And then the section in your main code becomes:
Code: Select all
for turn in xrange(1,11):
    print 'You are on turn '+str(turn)
    #makes sure player guesses a number:
    guess_row = get_input("row")
    guess_col = get_input("column")

You need to try to keep the main function as clean as possible.

-Mek
User avatar
Mekire
 
Posts: 987
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: First completed project - short/simple game

Postby ovisam » Sun Dec 29, 2013 3:41 pm

Thanks :) Here are the new/modified functions:

Code: Select all
def get_input(prompt):
    '''make sure the player guesses a number'''
    while True:
        guess=raw_input("Guess {} number: ".format(prompt))
        if guess.isdigit():
            return int(guess)-1
            break           
        print "Hmm, did you type a number? Please try again."


Code: Select all
def main():
    welcome()
    level=select_difficulty_level()
    print
    print "Let's play!\n"
    board=create_board()
    print_board(board)
    ship=generate_ship(level,board)
   
    for turn in xrange(1,11): 
        print 'You are on turn '+str(turn)
       
        guess_row = get_input("row")
        guess_col = get_input("column")
   
        #checks to see if player has guessed correctly:
        if [guess_row,guess_col] in ship:
            correct_guess(guess_row,guess_col,board,ship)
            if check_sunk(ship):
                print "Congratulations! You sunk my battleship!"
                break
        else:
            incorrect_guess(guess_row,guess_col,board)

    else:
        #if player has used up their 10 turns:
        print "You're out of turns! Game over."


Anything else I could do?
ovisam
 
Posts: 8
Joined: Sat Dec 21, 2013 12:13 am

Re: First completed project - short/simple game

Postby micseydel » Sun Dec 29, 2013 9:51 pm

Looks pretty good, congrats!
Join the #python-forum IRC channel on irc.freenode.net!

Please do not PM members regarding questions which are meant to be discussed publicly. The point of the forum is so that others can benefit from it. We don't want to help you over PMs or emails.
User avatar
micseydel
 
Posts: 1258
Joined: Tue Feb 12, 2013 2:18 am
Location: Mountain View, CA

Re: First completed project - short/simple game

Postby Mekire » Mon Dec 30, 2013 1:53 am

No need for the break; the function ends after the return.

Also I wanted to mention this:
Code: Select all
def check_sunk(ship):
    '''checks if ship has been sunk yet'''
    if ship.count(HIT)==2:
        return True
    else:
        return False

In cases like the above, you can just directly return the Boolean expression:
Code: Select all
def check_sunk(ship):
    """Checks if the ship has been sunk yet."""
    return ship.count(HIT) == 2

Still quite a bit of cleanup you can do in my opinion, but yes, it is looking pretty good.

-Mek
User avatar
Mekire
 
Posts: 987
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: First completed project - short/simple game

Postby ovisam » Tue Dec 31, 2013 5:44 pm

Thanks guys. How else could it be cleaned up?
ovisam
 
Posts: 8
Joined: Sat Dec 21, 2013 12:13 am


Return to Completed Scripts

Who is online

Users browsing this forum: No registered users and 2 guests