Registered User
Registered User

Reputation: 474

Python: AI not always placing his move in b-ship

In this code of b-ship:

import random
import time

def drawboard(aiboard,playerboard):
    print(' Opponent\'s          Your')
    print('    Ships            Ships')
    print('|   |   |   |    |   |   |   |')
    print('| ' + aiboard[7] + ' | ' + aiboard[8] + ' | ' + aiboard[9] + ' |    | ' + playerboard[7] + ' | ' + playerboard[8] + ' | ' + playerboard[9] + ' |')
    print('|   |   |   |    |   |   |   |')
    print('-------------    -------------')
    print('|   |   |   |    |   |   |   |')
    print('| ' + aiboard[4] + ' | ' + aiboard[5] + ' | ' + aiboard[6] + ' |    | ' + playerboard[4] + ' | ' + playerboard[5] + ' | ' + playerboard[6] + ' |')
    print('|   |   |   |    |   |   |   |')
    print('-------------    -------------')
    print('|   |   |   |    |   |   |   |')
    print('| ' + aiboard[1] + ' | ' + aiboard[2] + ' | ' + aiboard[3] + ' |    | ' + playerboard[1] + ' | ' + playerboard[2] + ' | ' + playerboard[3] + ' |')
    print('|   |   |   |    |   |   |   |')
def playerhitai(aiboard,players_chosen_hit,aishipplaces,playerboard,usershipspots):
    if players_chosen_hit in aishipplaces[0] or players_chosen_hit in aishipplaces[1]:
        aiboard[players_chosen_hit] = 'x'
        drawboard(aiboard,playerboard)
    else:
        aiboard[players_chosen_hit] = 'o'
        drawboard(aiboard,playerboard)

def hitaroundhit(aiboard, playerboard,aishipplaces,players_chosen_hit,usershipspots):
    spots = {1:[2,4],2:[1,3,5],3:[2,6],4:[1,5,7],5:[2,4,6,8],6:[3,5,9],7:[4,8],8:[5,7,9],9:[8,6]}
    spot_dict = random.choice(spots[players_chosen_hit])
    if playerboard[spot_dict] == 's':
        pickX(aiboard,players_chosen_hit,aishipplaces,playerboard,usershipspots)
        playerhitai(aiboard,players_chosen_hit,aishipplaces,playerboard,usershipspots)
    else:
        playerboard[spot_dict] = 'o'
        playerhitai(aiboard,players_chosen_hit,aishipplaces,playerboard,usershipspots)

def pickX(aiboard,players_chosen_hit,aishipplaces,playerboard,usershipspots,aitakenmoves):
    x = [1,2,3,4,5,6,7,8,9]
    firsthitattempt = random.choice(x)
    while x in aitakenmoves:
        firsthitattempt = random.choice(x)
    return firsthitattempt,aitakenmoves

def aihitplayer(aiboard,playerboard, usershipspots,players_chosen_hit,aishipplaces,aitakenmoves):
    x,z = pickX(aiboard,players_chosen_hit,aishipplaces,playerboard,usershipspots,aitakenmoves)
    if (aiboard[aishipplaces[0][0]] == 'x') and (aiboard[aishipplaces[0][1]] == 'x') and (aiboard[aishipplaces[1][0]] == 'x') and (aiboard[aishipplaces[1][1]] == 'x') and (aiboard[aishipplaces[1][2]] == 'x'):
        return z
    else:
        time.sleep(1)
        print("\nComputer's turn.\n")
        time.sleep(1)
        if x in usershipspots:
            playerboard[x] = 'x'
            drawboard(aiboard,playerboard)
        else:
            playerboard[x] = 'o'
            drawboard(aiboard,playerboard)
    return z

def getShipInfo(ship,possibleusershipplaces,usershipspots,playerboard):
    while True:
        try:
            ship = int(input('Enter the 5 locations of your ship. Start with ship one (2 spaces) then do ship two (3 spaces).'))
            if ship in possibleusershipplaces:
                break
        except ValueError:
            time.sleep(0.5)
            print("\nInvalid entry\n")
            time.sleep(0.5)
    while ship in usershipspots:
        try:
            ship = int(input('Spot already taken.'))
            if ship not in possibleusershipplaces:
                while True:
                    try:
                        ship = int(input('1-9 only!'))
                    except (ValueError, IndexError):
                        print('invalid input')
        except (ValueError, IndexError):
            time.sleep(0.5)
            print("\nInvalid entry\n")
            time.sleep(0.5)    
    playerboard[ship] = 's'
    usershipspots.append(ship)
    return playerboard,usershipspots
def ascii():
    print('''    dMMMMb  .aMMMb dMMMMMMP dMMMMMMP dMP     dMMMMMP .dMMMb  dMP dMP dMP dMMMMb''')
    time.sleep(0.02)
    print('''   dMP"dMP dMP"dMP   dMP      dMP   dMP     dMP     dMP" VP dMP dMP amr dMP.dMP''')
    time.sleep(0.02)
    print('''  dMMMMK" dMMMMMP   dMP      dMP   dMP     dMMMP    VMMMb  dMMMMMP dMP dMMMMP" ''')
    time.sleep(0.02)
    print(''' dMP.aMF dMP dMP   dMP      dMP   dMP     dMP     dP .dMP dMP dMP dMP dMP''')
    time.sleep(0.02)
    print('''dMMMMP" dMP dMP   dMP      dMP   dMMMMMP dMMMMMP  VMMMP" dMP dMP dMP dMP''')                             
    time.sleep(1)
def playagain():
    x = input("Play again? y/n")
    if x == 'yes' or x == 'y' or x == 'Yes' or x == 'Y':
        main()
    else:
        pass
def main():
    print()
    ascii()
    print()
    time.sleep(1)
    print('''
############################################################################
# Instructions:                                                            #
# You have a 3x3 board. So does the AI.                                    #
# Each person has 2 ships. One has a length of 2, other has a length of 3. #
# You can place the ships horizantally or vertically, not diagonally.      #
# You must try to hit the AI ships. Each move you get one shot.            #
# The player and AI alternates back and forth.                             #
# A hit is X and a miss is O. Your ships are designated with an S.         #
# Whoever hits all of the other\'s ships first, wins the game.              #
############################################################################
''')
    time.sleep(5)
    print()
    aitakenmoves = []
    twoships = [[1,2], [2,1], [1,4], [4,1], [2,3], [3,2], [2,5], [5,2], [3,6], [6,3], [4,5], [5,4], [4,7], [7,4], [5,6], [6,5], [5,8], [8,5], [6,9], [9,6], [7,8], [8,7], [8,9], [9,8]]
    threeships = [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,2,1], [3,1,2], [1,4,7], [1,7,4], [4,1,7], [4,7,1], [7,4,1], [7,1,4], [2,5,8], [2,8,5], [5,8,2], [5,2,8], [8,5,2], [8,2,5], [3,6,9], [3,9,6], [6,9,3], [6,3,9], [9,6,3], [9,3,6], [4,5,6], [4,6,5], [5,6,4], [5,4,6], [6,5,4], [6,4,5], [7,8,9], [7,9,8], [9,8,7], [9,7,8], [8,7,9], [8,9,7]]
    shipspots1 = random.choice(twoships)
    shipspots2 = random.choice(threeships)
    while (shipspots1[0] in shipspots2) or (shipspots1[1] in shipspots2):
        shipspots1 = random.choice(twoships)
        shipspots2 = random.choice(threeships)
    aishipplaces = [shipspots1,shipspots2]
    aiboard = [' ' for i in range(10)]
    playerboard = [' ' for i in range(10)]

    sh1sp1,sh1sp2,sh2sp1,sh2sp2,sh2sp3 = '','','','',''
    possibleusershipplaces = [1,2,3,4,5,6,7,8,9]
    players_inputted_hits = []
    usershipspots = []
    playerboard,usershipspots = getShipInfo(sh1sp1,possibleusershipplaces,usershipspots,playerboard)
    playerboard,usershipspots = getShipInfo(sh1sp2,possibleusershipplaces,usershipspots,playerboard)
    playerboard,usershipspots = getShipInfo(sh2sp1,possibleusershipplaces,usershipspots,playerboard)
    playerboard,usershipspots = getShipInfo(sh2sp2,possibleusershipplaces,usershipspots,playerboard)
    playerboard,usershipspots = getShipInfo(sh2sp3,possibleusershipplaces,usershipspots,playerboard)

    players_inputted_hits = []
    gameisplaying = True
    while gameisplaying:
        playersturn=True
        while playersturn:
            while True:
                try:
                    players_chosen_hit = int(input('Where do you want to try to hit the AI?: 1-9  '))
                    if players_chosen_hit in possibleusershipplaces:
                        if players_chosen_hit in players_inputted_hits:
                            while True:
                                try:
                                    players_chosen_hit = int(input('Already there! Try somewhere else!'))
                                    if players_chosen_hit not in players_inputted_hits:
                                        break
                                except ValueError:
                                    time.sleep(0.5)
                                    print("\nInvalid entry\n")
                                    time.sleep(0.5)
                        break
                except ValueError:
                    time.sleep(0.5)
                    print("\nInvalid entry\n")
                    time.sleep(0.5)
            players_inputted_hits.append(players_chosen_hit)
            playerhitai(aiboard, players_chosen_hit, aishipplaces, playerboard,usershipspots)
            playersturn = False
        aiturn = True
        while aiturn:
            aitakenmoves = aihitplayer(aiboard, playerboard, usershipspots,players_chosen_hit,aishipplaces,aitakenmoves)
            aiturn = False
        if (playerboard[usershipspots[0]] == 'x') and (playerboard[usershipspots[1]]) == 'x' and (playerboard[usershipspots[2]]) == 'x' and (playerboard[usershipspots[3]]) == 'x' and (playerboard[usershipspots[4]] == 'x'):
            print("AI WINS!")
            gameisplaying = False
        elif (aiboard[aishipplaces[0][0]] == 'x') and (aiboard[aishipplaces[0][1]] == 'x') and (aiboard[aishipplaces[1][0]] == 'x') and (aiboard[aishipplaces[1][1]] == 'x') and (aiboard[aishipplaces[1][2]] == 'x'):
            print("PLAYER WINS!")
            gameisplaying = False
    playagain()
main()

The AI is not always placing his move. It may be because his chosen move x = pickX() is already in the aiboard. I have made a list aitakenmoves to try to alleviate this condition, but it still persists. Any assistance?

Upvotes: 0

Views: 74

Answers (1)

BobChao87
BobChao87

Reputation: 155

The problem is occurring in the function pickX() where you are trying to use the aitakenmoves variables. There are two issues:

  1. The line

    aitakenmoves = []
    

    deletes your record of moves taken each time you run the function, so the first move the AI picks is always chosen, no matter what moves it has taken before.

  2. The aitakenmoves variable is not stored in the global scope (which is probably why you decided to initialize it each time the function is called), so the variable disappears after the pickX() function call ends. You will either want to keep track of the aitakenmoves as either

    • A) a variable in the main() function that you pass to aihitplayer() which in turn passes the variable to pickX(). You can then pass the choice back to main() from aihitplayer() by using a multiple return as you have in other places in your code. Or
    • B) a truly global variable, initialized before you call main() that you then access in the pickX() with the line

      global aitakenmoves

      that you can update directly in pickX().

I would personally recommend picking choice A, even though implementing choice B would definitely be easier to program since messing with global can be very confusing.

P.S. At least with the code given here, when the player wins, the AI still gets to take its turn.

EDIT: An abbreviated demonstration of how to implement choice A properly.

def pickX(aitakenmoves):
    firsthitattempt = random.randint(1, 9)
    while firsthitattempt in aitakenmoves:
        firsthitattempt = random.randint(1, 9)
    return firsthitattempt

def aihitplayer(aiboard,playerboard, usershipspots,players_chosen_hit,aishipplaces, aitakenmoves):
    x = pickX(aitakenmoves)

    time.sleep(1)
    print("\nComputer's turn.\n")
    time.sleep(1)
    if x in usershipspots:
        playerboard[x] = 'x'
        drawboard(aiboard,playerboard)
        return True, x #AI makes a hit
    else:
        playerboard[x] = 'o'
        drawboard(aiboard,playerboard)
        return False, x #AI misses

def main():
    # Initialization code
    aitakenmoves = []
    while gameisplaying:
        # Game loop
        ai_hit, location = aihitplayer(aiboard, playerboard, usershipspots,players_chosen_hit,aishipplaces,aitakenmoves)
        aitakenmoves.append(location)
        # Rest of game loop

Upvotes: 1

Related Questions