Ubuntu Forums ubuntu.com - launchpad.net - ubuntu help  

Go Back   Ubuntu Forums > The Ubuntu Forum Community > Other Community Discussions > Development & Programming > Programming Talk
Register Reset Password Forum Help Forum Council Search Today's Posts Mark Forums Read

Programming Talk
This forum is for all programming questions.
The questions do not have to be directly related to Ubuntu and any programming language is allowed.

 
Thread Tools Display Modes
Old January 11th, 2008   #1
NovaAesa
Dipped in Ubuntu
 
NovaAesa's Avatar
 
Join Date: Aug 2007
Location: Novocastria, Australia
Beans: 521
Ubuntu 9.04 Jaunty Jackalope
Send a message via MSN to NovaAesa
I just finished my first complete Python app!

Okay, I've been working on this for a few days now, and it's finally done. It's a game where you play Tic Tac Toe, also known as Naughts and Crosses in some countries.

It's written in Python and I've released it under the GPL so anyone can modify etc etc if they want to.

Constructive criticism is welcome, if you see any thing that I have done that is in any way un-pythonic please tell me. Also, could you mention whether you found the instructions within the app easy to understand?

So to run the programme, just change directories to the file, and type: (but I'm sure you all knew that )

Code:
python tic_tac_toe.py
Attached Files
File Type: gz tic_tac_toe.py.gz (4.4 KB, 73 views)
__________________
My Blog - starting up again!
Tag along as I journey through the world of Arch Linux!"
NovaAesa is offline   Reply With Quote
Old January 11th, 2008   #2
b0rka7a
Gee! These Aren't Roasted!
 
Join Date: Aug 2007
Location: /root
Beans: 216
Ubuntu 7.10 Gutsy Gibbon
Send a message via ICQ to b0rka7a Send a message via Skype™ to b0rka7a
Re: I just finished my first complete Python app!

Hehe You can't beat the computer
b0rka7a is offline   Reply With Quote
Old January 11th, 2008   #3
NovaAesa
Dipped in Ubuntu
 
NovaAesa's Avatar
 
Join Date: Aug 2007
Location: Novocastria, Australia
Beans: 521
Ubuntu 9.04 Jaunty Jackalope
Send a message via MSN to NovaAesa
Re: I just finished my first complete Python app!

I know It's an unbeatable algorithm. I didn't tell my brother that for a while (he tested it) and he got really frustrated at it!
__________________
My Blog - starting up again!
Tag along as I journey through the world of Arch Linux!"
NovaAesa is offline   Reply With Quote
Old January 11th, 2008   #4
Kadrus
Dipped in Ubuntu
 
Kadrus's Avatar
 
Join Date: Sep 2007
Location: λebanon
My beans are hidden!
Re: I just finished my first complete Python app!

Nice..I really suck at the game though..lol.
Kadrus is offline   Reply With Quote
Old January 11th, 2008   #5
Majorix
Fresh Brewed Ubuntu
 
Majorix's Avatar
 
Join Date: Mar 2007
Location: Turkey
Beans: 1,449
Re: I just finished my first complete Python app!

Why don't you paste your code on a pastebin so that we can see it without downloading?
__________________
BeginnersTeam Member
Majorix is offline   Reply With Quote
Old January 11th, 2008   #6
Kadrus
Dipped in Ubuntu
 
Kadrus's Avatar
 
Join Date: Sep 2007
Location: λebanon
My beans are hidden!
Re: I just finished my first complete Python app!

Here's the code..it's the same thing.. created by NovaAesa
PHP Code:
#!/usr/bin/python

import random

class TicTacToe(object):
    
"""A TicTacTow class
    """
    
    
MID  = ((11),)  #middle square
    
SIDE = ((01), (10), (12), (21))  #side squares
    
CORN = ((00), (02), (20), (22))  #corner squares
    
    
def __init__(selfcomp_firstcomp_chr='X'player_chr='O'):
        
"""Starts up the class
        Parameters: comp_first - Decides who goes first, True for the computer
                                 or False for the player.
                    comp_chr   - The symbol used for the computer. Should be a
                                 single length string.
                    player_chr - The symbol used for the player. Should be a
                                 single length string.
        """
        
self._grid = {}  #keys: 2-tuple coords, values: comp_chr or player_chr
        
self._computer comp_chr
        self
._player player_chr
        self
._branch ""  #the branch that that is being played
                           #(corner='a', edge='b', center='c')
        
self._last_move 0  #The last move played by the computer. Values are
                             #0, 1, 2, 3, and 5
        
self._comp_first comp_first  #Records who went first. True is
                                       #computer went first, False is player
                                       #went first.
        
    
def get_first_move(self):
        
"""Returns: The playing field grid with the computer's first move.
        This method should only be called if the object was created with
        comp_first=True, and then only once at the start"""
        
if self._last_move == and self._comp_first:
            
first_move self._comp_move()[0]
            
self._last_computer_move first_move
            self
._grid[first_move] = self._computer
            
return self._grid
        
else:
            print 
"RAISE ERROR"
        
    
def submit(selfmove):
        
"""Submits a move.
        
        Returns: A tuple containing the _grid dictionary (including the
        computer's new move) and a string value indicating a win-tie situation.
        Values for the string are 'win', and 'tie' (there is no lose value
        since the computer never loses :P).
        """
        
self._grid[move] = self._player
        self
._last_player_move move
        
if self._comp_first:  #computer went first
            
new_movewin_tie_value self._comp_move()
            
self._last_computer_move new_move
            self
._grid[new_move] = self._computer
        
else:  #player went first
            
if self._last_move == 4:
                
#On the last move, the computer shouldn't generate a response
                #If the player is able to make a last move, it will always be
                #a tie, because the computer cannot lose.
                
win_tie_value "tie"
            
else:
                
new_movewin_tie_value self._player_move()
                
self._last_computer_move new_move
                self
._grid[new_move] = self._computer
        
return (self._gridwin_tie_value)
        
    
def _win(self):
        
"""Checks to see if the computer can win on the next turn.
        Returns: The coordinates in a tuple if the win can take place.
        Otherwise, None is returned.
        """
        
pass
    
    def _two_line
(selfwin_or_block):
        
"""Checks to see if the computer should block or take a win. This
        happens if there is two of the same piece in a line and the other
        spot in the line is blank.
        
        Parameters: win_or_block - Decides if the algorithm looks for a
                                   possible win or a block that needs to take
                                   place. 'win' and 'block' are the only
                                   possible values.
        
        Returns: The coordinates in a tuple if the block should take place or
        the win can take place. Otherwise, None is returned.
        """
        
seq = [(((0,0),(1,0),(2,0)), ((0,1),(1,1),(2,1)), ((0,2),(1,2),(2,2))), 
               (((
0,0),(0,1),(0,2)), ((1,0),(1,1),(1,2)), ((2,0),(2,1),(2,2))),
               (((
0,2),(1,1),(2,0)), ((0,0),(1,1),(2,2)))] #line 1 - rows
                                                           #line 2 - column
        
for line_type in seq:                              #line 3 - diagonals
            
for member in line_type:
                
piece_counter 0  #counts the pieces in the row/column/diag
                
empty_counter 0  #counts the empty places
                
for xy in member:
                    if (
xynot in self._grid.keys():
                        
empty_counter += 1
                        return_x 
x
                        return_y 
y
                    
else:
                        if 
win_or_block == 'win':
                            if 
self._grid[xy] == self._computer:
                                
piece_counter += 1
                        elif win_or_block 
== 'block':
                            if 
self._grid[xy] == self._player:
                                
piece_counter += 1
                    
if piece_counter == and empty_counter == 1:
                        return (
return_xreturn_y)

        return 
None  #returns None if no blocks have been found
        
    
def _comp_move(self):
        
"""Returns the best move for the computer to make next if the compter
        went first initially.
        The moves are done according to the logic tree. In the tree X is the
        computer and O is the player.
                                      |
        1                         X-corner
                 _____________________|__________________________ 
                |                     |                          |
            O-corner               O-edge                    O-center   
                |                     |                          |
        2   X-corner(a)           X-center(b)            X-caddy_corner(c)
                |                     |                   _______|________ 
                |                     |                  |                |
             O-block               O-block           O-corner          O-edge   
                |                _____|_____             |                |
                |               |           |            |            ....|....
        3   X-corner      X-block     X-corner       X-corner         .X-block.
                                      not_bordered                    .........
        """
        
        
status None  #default value for status
        #first checks if there are any winning moves
        
if self._two_line("win") != None:
            
square self._two_line("win")
            
status "win"
        
else:
        
            
#this is the first move
            
if self._last_move == 0:
                
square self._rnd_corner()
                
self._last_move 1
                
            
#this is the second move
            
elif self._last_move == 1:
                if 
self._last_player_move in self.CORN:
                    
self._branch 'a'
                    
square self._rnd_corner()
                
elif self._last_player_move in self.SIDE:
                    
self._branch 'b'
                    
square, = self.MID
                elif self
._last_player_move in self.MID:
                    
self._branch 'c'
                    
xself._last_computer_move
                    square 
= (xy)  
                
self._last_move 2
            
            
#this is the third move      
            
elif self._last_move == 2:  
                if 
self._branch == 'a':
                    
square self._rnd_corner()
                
elif self._branch == 'b':
                    if 
self._two_line("block") != None:
                        
square self._two_line("block")    
                    else:
                        
possible_corners = []
                        for 
corner in self.CORN:
                            if 
corner not in self._grid.keys():
                                
possible_corners.append(corner)
                        for 
xy in possible_corners
                            if (
x1not in self._grid.keys() and 
                               (
1ynot in self._grid.keys():
                                
square xy
                elif self
._branch == 'c':
                    if 
self._last_player_move in self.CORN:
                        
square self._rnd_corner()
                    
elif self._last_player_move in self.SIDE:
                        
square self._two_line("block"
                
self._last_move 3
            
            
#This is move 4 & 5. It is only executed in response to a c-branch
            
else:                                                        #draw
                
square self._two_line("block")
                if 
self._last_move == 4:
                    
status "tie"
                
self._last_move += 1
            
        
return (squarestatus)
        
    
def _player_move(self):
        
"""Returns the best move for the computer to make next if the player
        went first initially.
        The moves are done according to the logic tree. In the tree X is the
        computer and O is the player. Dotted lines indicates repition after
        the first run through.
        
                 __________________________|_______
                |(a)                               |(b)
            O-center                          O-not_center
                |                                  |
    1       X-corner                            X-center
                |                 _________________|__________________      
       .........|........        |                 |                  |
       .   O-any-move   . O-1edge,1corner     O-both-edge       O-both-corner
       .    ____|___    .     ___|____          ___|____          ____|___
       .   |        |   .    |        |        |        |        |        |
       .   |        |   .    |        |  both-edges  one-edge    |        |
       .   |        |   .    |        |brder-corner  brder-corner|        |
       .   |        |   .    |(ba)    |(bb)    |(bc)    |(bd)    |(be)    |(bf)
    2  .X-block X-corner. X-block  X-caddy X-cornered X-edge  X-block  X-edge
       ..................    |     corner    square     |        |        |
                         ....|... ....|...  ...|....    |     ...|.... ...|....
                         .block/. .block/.  .block/. O-block  .block/. .block/.
                         .random. .random.  .random.    |     .random. .random.
                         ........ ........  ........    |     ........ ........
    3                                             X-corner-next
                                                    to-X-edge
        """
        
status None  #default value of status is None
        #first checks if there are any winning moves
        
if self._two_line("win") != None:
            
square self._two_line("win")
            
status "win"
        
else:
            
            
#this is the first move
            
if self._last_move == 0:
                if 
self._last_player_move in self.MID:
                    
square self._rnd_corner()
                    
self._branch 'a'
                
else:
                    
square, = self.MID
                    self
._branch 'b'
                
self._last_move 1
                    
            
#this is the second move
            
elif self._last_move == 1:
                if 
self._branch == 'a':
                    if 
self._two_line("block") != None:
                        
square self._two_line("block")
                    else:
                        
square self._rnd_corner()
                
elif self._branch == 'b':
                    
side_count 0
                    corner_count 
0
                    
for xy in self._grid.keys():
                        if 
self._grid[xy] == self._player:
                            if (
xyin self.SIDE:
                                
side_count += 1
                            elif 
(xyin self.CORN:
                                
corner_count += 1
                    
if side_count == and corner_count == 1:
                        if 
self._two_line("block") != None:
                            
square self._two_line("block")
                            
self._branch "ba"
                        
else:
                            for 
xy in self.CORN:
                                if (
xyin self._grid.keys():
                                    if 
self._grid[xy] == self._player:
                                        
square = (xy)
                                        
self._branch "bb"
                    
elif side_count == 2:
                        
side_pieces = []
                        for 
xy in self.SIDE:
                            if (
xyin self._grid.keys():
                                
side_pieces.append((xy))
                        
x1y1 side_pieces[0]
                        
x2y2 side_pieces[1]
                        if 
abs(x1 x2) == 1:
                            if 
x1 != 1:
                                
new_x x1
                            
else:
                                
new_x x2
                            
if y1 != 1:
                                
new_y y1
                            
else:
                                
new_y y2
                            square 
= (new_xnew_y)
                            
self._branch "bc"
                        
else:
                            
square self._rnd_side()
                            
self._branch "bd"
                    
elif corner_count == 2:
                        if 
self._two_line("block") != None:
                            
square self._two_line("block")
                            
self._branch "be"
                        
else:
                            
square self._rnd_side()
                            
self._branch "bf"
                
self._last_move 2
                                
            
#this is the third move
            
elif self._last_move == 2:
                
#branch 'a'
                
if self._branch == 'a':
                    if 
self._two_line("block") != None:
                        
square self._two_line("block")
                    else:
                        
square self._rnd_corner()
                
#all other branches
                
elif self._branch in ("ba""bb""bc""be""bf"):
                    if 
self._two_line("block") != None:
                        
square self._two_line("block")
                    else:
                        
square self._rnd_square()
                
#branch "bd"
                
elif self._branch == "bd":
                    
possible = []
                    
last_xlast_y self._last_computer_move
                    
for xy in self.CORN:
                        if 
== last_x or == last_y:
                            
possible.append((xy))
                    
square random.choice(possible)
                
self._last_move 3
                
            
#this is the fourth move
            
elif self._last_move == 3:
                if 
self._two_line("block") != None:
                    
square self._two_line("block")
                else:
                    
square self._rnd_square()
                
self._last_move 4        
                
        
return (squarestatus)
        
    
def _rnd_side(self):
        
"""Returns: a tuple containing the coordinates to a random side edge
        that has yet to be taken.
        """
        
while True:
            
xrandom.choice(self.SIDE)
            if (
xynot in self._grid.keys(): break
        return (
xy)
  
    
def _rnd_corner(self):
        
"""Returns: a tuple containing the coordinates to a random corner
        that has yet to be taken.
        """
        
while True:
            
xrandom.choice(self.CORN)
            if (
xynot in self._grid.keys(): break
        return (
xy)
        
    
def _rnd_square(self):
        
"""Returns: a tuple containing the coordinates to a random square
        that has yet to be taken.
        """
        
possible = []
        for 
x in range(3):
            for 
y in range(3):
                if (
xynot in self._grid.keys():
                    
possible.append((xy))
        return 
random.choice(possible)
        
def string_grid(grid):
    
"""Creates a string version of a 3x3 Tic Tac Toe grid.
    
    Parameters: grid - the grid that is to be created
    
    Returns: a string representation of grid.
    """
    
output_string "\n"
    
for y in range(3):
        for 
x in range(3):
            if (
xyin grid.keys():
                
output_string += grid[xy] + " "
            
else:
                
output_string += '- '
        
output_string += '\n'
    
return output_string
    
def get_input
(tictactoe_obj):
    
"""Gets input from the user about which position they wish to put their
    piece. Entered corespond with the following positions: 7 8 9
                                                           4 5 6
    tictactoe_obj is the current game being played.        1 2 3

    Returns: A tuple containing the coordinates of the piece.
    """
    
    
while True:
    
        
#Gets a set of coordinates
        
while True:
            
valid_num False
            user_input 
raw_input("Please enter a number between 1 and 9:\n")
            if 
user_input in ('1''2''3''4''5''6''7''8''9'):
                
valid_num True
                x 
= (int(user_input) - 1) % 3
                y 
- (int(user_input) - 1// 3
                
coord = (xy)
            else:
                print 
"Invalid answer"
            
if valid_num: break
        
        
#makes sure the coordinates aren't already taken
        
if coord not in tictactoe_obj._grid.keys():
            
taken False
        
else:
            
taken True
            
print "That place is already taken"
            
        
if not taken: break

    return 
coord
        
if __name__ == '__main__':

    
#initialises score counters (there is no player_wins because
    
computer_wins 0  #the player cannot win)
    
ties 0
    
    
#prints instructions
    
print "****************************************"
    
print "*                                      *"
    
print "*         Tic Tac Toe 1.0.0            *"
    
print "*                                      *"
    
print "****************************************"
    
print "                                        "
    
print "Tic Tac Toe is released under the       "
    
print "GPL (c) 2008 Peter Stace.               "
    
print "                                        "
    
print "Instructions:                           "
    
print "When entering a place to put a piece,   "
    
print "use the number pad to enter a number    "
    
print "between 1 and 9. The position on the    "
    
print "number on the number pad coresponds to  "
    
print "the square as follows:                  "
    
print "                                        "
    
print "         7 | 8 | 9                      "
    
print "        ---+---+---                     "
    
print "         4 | 5 | 6                      "
    
print "        ---+---+---                     "
    
print "         1 | 2 | 3                      "
    
print "                                        "
    
print "The computer is X and the player is O   "
    
print "                                        "
    

    
computer_first False
    
while True:
        
computer_first not computer_first
        
        
#says who will go first
        
current_game TicTacToe(computer_first)
        if 
computer_first:
            print 
"\nComputer goes first"
            
print string_grid(current_game.get_first_move())
        else:
            print 
"\nPlayer goes first"
        
        
#plays the game    
        
while True:
            
gridstatus current_game.submit(get_input(current_game))
            print 
string_grid(grid)
            if 
status != None:
                if 
status == "win":
                    print 
"The computer has won\n"
                    
computer_wins += 1
                elif status 
== "tie":
                    print 
"You have tied against the computer\n"
                    
ties += 1
                
print """Score:\n\nComputer: %s\nPlayer: 0\nTies: %s\n""" 
                                                        
% (computer_winsties)
            if 
status != None: break
            
        
#finds out if the player wants to play again
        
while True:
            
answer raw_input("Would you like to play again? y/n ")
            if 
answer not in ('y''n'):
                print 
"Please answer y or n"
                
valid_answer False
            
else:
                
valid_answer True
            
if valid_answer == True: break
        if 
answer == 'n': break 
Kadrus is offline   Reply With Quote
Old January 11th, 2008   #7
Mr.popo
A Carafe of Ubuntu
 
Join Date: Oct 2007
Beans: 140
Re: I just finished my first complete Python app!

I tied.
Mr.popo is offline   Reply With Quote
Old January 11th, 2008   #8
Kadrus
Dipped in Ubuntu
 
Kadrus's Avatar
 
Join Date: Sep 2007
Location: λebanon
My beans are hidden!
Re: I just finished my first complete Python app!

Quote:
Originally Posted by Mr.popo View Post
I tied.
So did I..twice ..
Kadrus is offline   Reply With Quote
Old January 13th, 2008   #9
NovaAesa
Dipped in Ubuntu
 
NovaAesa's Avatar
 
Join Date: Aug 2007
Location: Novocastria, Australia
Beans: 521
Ubuntu 9.04 Jaunty Jackalope
Send a message via MSN to NovaAesa
Re: I just finished my first complete Python app!

So does anyone have any constructive criticism? I'm sure I must have done something wrong.
__________________
My Blog - starting up again!
Tag along as I journey through the world of Arch Linux!"
NovaAesa is offline   Reply With Quote
Old January 13th, 2008   #10
Jessehk
Ubuntu Extra Shot
 
Jessehk's Avatar
 
Join Date: Jul 2005
Location: Ontario, Canada
Beans: 367
Ubuntu 7.04 Feisty Fawn
Re: I just finished my first complete Python app!

You could try writing a dynamic tree (and use something like a minimax algorithm) instead of hardcoding the possibilities in.

I had fun doing just that in C++.
Jessehk is offline   Reply With Quote

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 06:18 PM.


vBulletin ©2000 - 2010, Jelsoft Enterprises Ltd. Ubuntu Logo, Ubuntu and Canonical © Canonical Ltd. Tango Icons © Tango Desktop Project. lingonberry