Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  

Author Topic: Learning Python  (Read 1337 times)

Omegastick

  • Bay Watcher
  • Crazy musician man
    • View Profile
Learning Python
« on: December 29, 2010, 10:26:02 am »

Hello there all!

Some of you may know me, some of you may not, but I need your help regardless of this fact. You see, for about two years now I've been trying to learn Python and failing in a horrible and OTT manner but I've decided to try and enlist the help of you guys. I'll post my current projects here in this thread and you guys can help me figure out what I've done wrong (if you so choose)!

The first project I've decided to post is a Tic-Tac-Toe AI, although the AI isn't even near implemented yet, I've run into trouble with the Tic-Tac-Toe game itself. The game has gone through several stages, and at one point I even had it fully working, but this wasn't compatible with the AI and I started over. Here is the latest version:

Code: [Select]
#             #
# Tic-Tac-Toe #
#             #

# Initialize

area = {1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0}

play = 1

def printarea():
    print area[1], area[2], area[3]
    print area[4], area[5], area[6]
    print area[7], area[8], area[9]

def playermove(move):
    if area[move] == 0:
        area[move] = 1
        return 1
    else:
        print 'Invalid move'
        playermove()
        return 0

playcorrect = 0

# Game

while play == 1:
    printarea()
    print ' '
    playermove(raw_input('Please make a move: '))

Please note that for debugging purposes I've removed the 'X' and 'O' visuals and replaced it with '0', '1' and '2'. '0' is nothing, '1' is X and '2' is O (although this isn't in yet).

Upon running it it produces this:

Code: [Select]
>>>
0 0 0
0 0 0
0 0 0
 
Please make a move: 1

Traceback (most recent call last):
  File "C:\Python26\Projects\XOX.py", line 32, in <module>
    playermove(raw_input('Please make a move: '))
  File "C:\Python26\Projects\XOX.py", line 17, in playermove
    if area[move] == 0:
KeyError: '1'
>>>

Any help with fixing this problem?
Logged
I make music under the name Flag Red, check me out:
Soundcloud
Youtube
Facebook

ILikePie

  • Bay Watcher
  • Call me Ron
    • View Profile
Re: Learning Python
« Reply #1 on: December 29, 2010, 11:35:38 am »

raw_input() returns a string, so it should look like so:
Code: [Select]
def playermove(move):
    if area[int(move)] == 0:
        area[int(move)] = 1
        return 1
    else:
        print 'Invalid move'
        playermove()
        return 0
or like so:
Code: [Select]
...
    playermove(int( raw_input('Please make a move: ') ))
« Last Edit: December 29, 2010, 11:39:06 am by ILikePie »
Logged

Omegastick

  • Bay Watcher
  • Crazy musician man
    • View Profile
Re: Learning Python
« Reply #2 on: December 29, 2010, 11:52:23 am »

Excellent, thank you! That 'raw_input' was still left from before I reworked the whole thing, I've changed it to an 'input' to fix it.

On another note, I can see three options for making the AI before me:

1) Program a reaction to every possible move. Pros: easy and always wins. Cons: repetitive, time consuming.

2) Make it a learning AI, I will keep a text file with the winning moves in and when it decides what move to use it will be affected by the text file. Pros: good test of my programming skill and it is a clever idea. Cons: Have to train it, possibly time consuming and I may not be up to the task.

3) Make it go through every possible move in the game and pick the move with the most 'win' outcomes. Pros: Always wins, clever. Cons: time consuming and difficult.
Logged
I make music under the name Flag Red, check me out:
Soundcloud
Youtube
Facebook

lordnincompoop

  • Bay Watcher
  • Allusionist
    • View Profile
Re: Learning Python
« Reply #3 on: December 29, 2010, 11:57:52 am »

There. You're welcome. :P

Input for the player move, the computer always picks the optimal move. It's the easiest (perhaps even best) way through, and learning AI might be a bit too complex for you right now.

Not to mention that it won't be optimal.
Logged

ILikePie

  • Bay Watcher
  • Call me Ron
    • View Profile
Re: Learning Python
« Reply #4 on: December 29, 2010, 11:59:24 am »

You gotta love xkcd :-P

e, Dude...
Logged

Omegastick

  • Bay Watcher
  • Crazy musician man
    • View Profile
Re: Learning Python
« Reply #5 on: December 29, 2010, 05:04:45 pm »

Funnily enough, it's that comic that inspired me to make this!

Aw crap, just spent about half an hour doing repetitive searching trees only to have my computer crash and lose all my data. Oh well, I can do it in a more efficient manner now.
« Last Edit: December 29, 2010, 05:06:42 pm by Omegastick »
Logged
I make music under the name Flag Red, check me out:
Soundcloud
Youtube
Facebook

Frajic

  • Bay Watcher
    • View Profile
Re: Learning Python
« Reply #6 on: December 29, 2010, 05:23:17 pm »

Suggestion for a not-unfair/more human AI(not that tic-tac-toe isn't a horribly unbalanced game anyway):
-Make it choose random squares, but prefer the middle one if possible(that's what most people do)
-Make it find rows it's only one piece from winning from, and choose those over random ones
-Make it find rows the player is only one piece from winning from, and choose that over the others if it doesn't have a row it can win with

...you know, I should just shut up and make this myself. Then again, I'll be busy tomorrow...

brb firing up Python
Logged
EoS company name: Vikings Inc.

lordnincompoop

  • Bay Watcher
  • Allusionist
    • View Profile
Re: Learning Python
« Reply #7 on: December 29, 2010, 05:28:39 pm »

I'll be making a C++ implementation. Seems interesting.

Once I'm done I'll go ahead and post it in the Bay12prog thread.
Logged

Omegastick

  • Bay Watcher
  • Crazy musician man
    • View Profile
Re: Learning Python
« Reply #8 on: December 29, 2010, 06:13:24 pm »

New problem that I'm not entirely sure how to fix. I've made it to check each turn for if the player has won and print a congratulatory message if they have. However, simply nothing happens.

Code: [Select]
#             #
# Tic-Tac-Toe #
#             #

# Initialize

area = {1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0}

play = 1

def printarea():
    print area[1], area[2], area[3]
    print area[4], area[5], area[6]
    print area[7], area[8], area[9]

def player1move(move):
    if area[move] == 0:
        area[move] = 1
        if checkh(1,move) == 1:
            return 2
        elif checkv(1,move) == 1:
            return 2
        elif checkd(1,move) == 1:
            return 2
        else:
            return 1
    else:
        print 'Invalid move'
        player1move(input('Please make a move: '))
        return 0

def player2move(move):
    if area[move] == 0:
        area[move] = 2
        if checkh(2,move) == 1:
            return 2
        elif checkv(2,move) == 1:
            return 2
        elif checkd(2,move) == 1:
            return 2
        else:
            return 1
   
    else:
        print 'Invalid move'
        player2move(input('Please make a move: '))
        return 0

def checkh(move, player):
    if move == 1 or 4 or 7:
        if area[move] + 1 == player:
            if area[move] + 2 == player:
                return player
        else:
            return 0
    if move == 2 or 5 or 8:
        if area[move] - 1 == player:
            if area[move] + 1 == player:
                return player
        else:
            return 0
    if move == 3 or 6 or 9:
        if area[move] - 1 == player:
            if area[move] - 2 == player:
                return player
        else:
            return 0

def checkv(move, player):
    if move == 1 or 2 or 3:
        if area[move] + 3 == player:
            if area[move] + 6 == player:
                return player
        else:
            return 0
    if move == 4 or 5 or 6:
        if area[move] - 3 == player:
            if area[move] + 3 == player:
                return player
        else:
            return 0
    if move == 7 or 8 or 9:
        if area[move] - 3 == player:
            if area[move] + 3 == player:
                return player
        else:
            return 0

def checkd(move, player):
    if move == 1:
        if 5 == player:
            if 9 == player:
                return player
        else:
            return 0
    if move == 3:
        if 5 == player:
            if 7 == player:
                return player
        else:
            return 0
    if move == 7:
        if 5 == player:
            if 3 == player:
                return player
        else:
            return 0
    if move == 9:
        if 5 == player:
            if 1 == player:
                return player
        else:
            return 0
   
playcorrect = 0

# Game

while play == 1:
    printarea()
    print ' '
    if player1move(input('Please make a move: ')) == 2:
        print 'player 1 has won!'
        play = 0
    print ' '
    printarea()
    print ' '
    print 'Player 2\'s move'
    print ' '
    if player2move(input('Please make a move: ')) == 2:
        print 'player 2 has won!'
        play = 0
    print ' '
Logged
I make music under the name Flag Red, check me out:
Soundcloud
Youtube
Facebook

Frajic

  • Bay Watcher
    • View Profile
Re: Learning Python
« Reply #9 on: December 29, 2010, 07:01:56 pm »

Done. All that's left is an option to let the computer take the first turn, and a better interface. But it's very much playable.

Code: [Select]
# A simple tic-tac-toe game, with a "human" artificial intelligence opponent.
# For reference purposes both the computer and user is referred to as players.

from random import randint

# The fields. A "0" means empty, a "1" means X, a "2" means O.
field = {1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0}

# The fields, visualised
vfield = "   \n   \n   "

# The user's unit type(X by default).
usertype = 1

# The computer's unit type(O by default).
comtype = 2

# The redrawing of the visualised fields
def redrawfields():
    global field
    global vfield
    vfield = ""
    count = 0
    for entry in field:
        if count == 3:
            vfield += "\n"
            count = 0
        if field[entry] == 0:
            vfield += " "
        elif field[entry] == 1:
            vfield += "X"
        else:
            vfield += "O"
        count += 1

# The computer's movement.
def computermove():
    global field
    global usertype
    global comtype
    # All possible rows.
    row1 = [1, 2, 3]
    row2 = [4, 5, 6]
    row3 = [7, 8, 9]
    row4 = [1, 4, 7]
    row5 = [2, 5, 8]
    row6 = [3, 6, 9]
    row7 = [1, 5, 9]
    row8 = [3, 5, 7]
    rows = [row1, row2, row3, row4, row5, row6, row7, row8]
    # Finds out if the opponent is about to win, or if the computer is about to win. The "danger" and "win" variables also act as a positioners.
    danger = 0
    win = 0
    for row in rows:
        totalopponent = 0
        for entry in row:
            if field[entry] == usertype:
                totalopponent += 1
            elif field[entry] == comtype:
                totalopponent -= 1
        if totalopponent == 2:
            for entry in row:
                if field[entry] == 0:
                    danger = entry
                    break
            break
        elif totalopponent == -2:
            for entry in row:
                if field[entry] == 0:
                    win = entry
                    break
            break
    # Checks if all the fields are taken
    takenfields = 0
    for entry in field:
        if field[entry] != 0:
            takenfields += 1
    # Finds out what to do
    if takenfields == 9:
        return 0
    elif win != 0:
        field[win] = comtype
    elif danger == 0:
        if field[5] == 0:
            field[5] = comtype
        else:
            while True:
                a = randint(1, 9)
                if field[a] == 0:
                    field[a] = comtype
                    break
    else:
        field[danger] = comtype

# Finds out if someone has won.
def win():
    # Borrows the code from computermove
    global field
    global usertype
    global comtype
    row1 = [1, 2, 3]
    row2 = [4, 5, 6]
    row3 = [7, 8, 9]
    row4 = [1, 4, 7]
    row5 = [2, 5, 8]
    row6 = [3, 6, 9]
    row7 = [1, 5, 9]
    row8 = [3, 5, 7]
    rows = [row1, row2, row3, row4, row5, row6, row7, row8]
    for row in rows:
        totalopponent = 0
        for entry in row:
            if field[entry] == usertype:
                totalopponent += 1
            elif field[entry] == comtype:
                totalopponent -= 1
        if totalopponent == 3:
            return 1
            break
        elif totalopponent == -3:
            return 2
            break
    takenfields = 0
    for entry in [1, 2, 3, 4, 5, 6, 7, 8, 9]:
        if field[entry] != 0:
            takenfields += 1
    if takenfields == 9:
        return 3
    return 0

# Here the script starts.

#Prints the intro.
print "This is a simple game of Tic-Tac-Toe."
print "You'll be playing against a computer opponent."
print "You choose which field to fill by entering the corresponding number."
print "The fields in the first row are 1, 2, and 3, and so on."
print " "
# Finds out which unit type the user wants.
while True:
    print "Would you like to play as X or O?"
    choice = raw_input("> ")
    if choice == "X" or choice == "x":
        usertype = 1
        comtype = 2
        break
    elif choice == "O" or choice == "o":
        usertype = 2
        comtype = 1
        break
    else:
        "That's not a valid entry. Only X/x or O/o, please."

print " "
print "Game start!"

#Here the game of tic-tac-toe starts. It checks whether anyone has one or if it's become a tie.
while win() == 0:
    print " "
    print vfield
    print " "
    choice = input("Which field do you choose? ")
    if field[choice] != 0:
        print "That field's already taken."
    else:
        field[choice] = usertype
        if win() == 1:
            break
        computermove()
        redrawfields()
redrawfields()
print " "
print vfield
print " "
if win() == 1:
    print "You won!"
elif win() == 2:
    print "The computer won!"
else:
    print "It's a tie!"

Excuse me while I go off to bed.
« Last Edit: December 29, 2010, 07:09:39 pm by Dwarf Midget »
Logged
EoS company name: Vikings Inc.

Bricks

  • Bay Watcher
  • Because you never need one brick.
    • View Profile
Re: Learning Python
« Reply #10 on: December 31, 2010, 03:06:48 am »

Omegastick, your checkh/checkv/checkd functions are a little confusing.  I'm not sure that they work the way you seem to want to use them; nor do you seem to be sending the input in the correct format.

I made a genetic algorithm for tic-tac-toe AI recently.  It's a pretty interesting problem, considering that the method I used appeared to never allow the "perfect" AI to come about, so there was some constant competition when I made two populations play against each other.
Logged
EMPATHY - being able to feel other peoples' stuff.