python battleship.py

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python battleship.py相关的知识,希望对你有一定的参考价值。

#!/usr/bin/python
# -*- coding: UTF-8 -*-
# battleship game

import sys
import random

def is_valid_int(integer):
  """
  checks to see if number represents a valid integer
  @number: a string that might represent an integer
  @returns: true if the string represents an integer
  """
  integer = integer.strip()
  if len(integer) == 0:
    return False
  else:
    return (integer.isdigit() or #only digits
            #or a negative sign followed by digits
            (integer.startswith('-') and integer[1:].isdigit()))
# end is_valid_int

def check_is_valid_file(file_name, board, width, height, ai_board):
    """
    check if the file meets the need
    @file_name: the file name that player input
    @board:     the player's board
    @width:     board's width
    @height:    board's height
    @ai_board:  AI's board
    @returns:   print messages list
    """
    # open the file with default mode "r"(read)
    # if the file does't exit or other errors occurs
    # the program'll exit with 0
    try:
        file_to_read = open(file_name)
    except:
        print("Open file error!")
        print("Terminating game.")
        sys.exit(0)

    # list for symbols eg.'['P', 'A']'
    symbols_for_ship = []
    # remember the info of the user's ship
    # for drawing the AI's ships
    placements_info = []

    # read the file line by line
    for each_line in file_to_read:
        # delete the ' ' and '\n' chars in this line
        # prepare for later process
        each_line = each_line.strip('\n')

        # minus index number is not permitted
        if '-' in each_line:
            print("Error %s is placed outside of the board." % each_line[0])
            file_to_read.close()
            print("Terminating game.")
            sys.exit(0)

        # now placement is an array like '['A', '1', '1', '2', '1']'
        placement = list(each_line)
        # clear the space
        placement = list(filter(lambda x: x != " ", placement))
        placements_info.append(placement)

        # get the symbol of the ship
        symbol = placement[0]
        if symbol in ["x", "X", "o", "O", "*"]:
            print("You should not use the reserved symbols.")
            file_to_read.close()
            print("Terminating game.")
            sys.exit(0)

        # to check whether it has duplicate elements
        if symbol in symbols_for_ship:
            # symobl is in the list
            # exit the process
            print("Error symbol %s is already in use." % symbol)
            # close the file
            file_to_read.close()
            print("Terminating game")
            sys.exit(0)
        else:
            # symobl is not in the list, put it in the list
            symbols_for_ship.append(symbol)

        # check if user placed the ship diagonally
        point_one_x = int(placement[1])
        point_one_y = int(placement[2])
        point_two_x = int(placement[3])
        point_two_y = int(placement[4])
        if point_one_x != point_two_x and point_one_y != point_two_y:
            print("Ships cannot be placed diagonally.")
            file_to_read.close()
            print("Terminating game.")
            sys.exit(0)

        # point is (3, 0) but height is 3, the point is still out the board
        # so this should be >=
        if point_one_x >= height or point_two_x >= height or point_one_y >= width or point_two_y >= width:
            print("Error %s is placed outside of the board." % each_line[0])
            file_to_read.close()
            print("Terminating game.")
            sys.exit(0)

        # put the ship in the board to check whether place their ships on top of each other
        if point_one_x == point_two_x:
            # ship is horizontal
            # guarantee point_one_y is less than point_two_y
            if point_one_y > point_two_y:
                # exchange the values
                (point_one_y, point_two_y) = (point_two_y, point_one_y)

            for y in range(point_one_y, point_two_y + 1):
                if board[point_one_x][y] != "*":
                    # print("You place the ship on top of each other")
                    print("There is already a ship at location %d, %d." % (point_one_x, y))
                    file_to_read.close()
                    print("Terminating game.")
                    sys.exit(0)
                board[point_one_x][y] = symbol
        else:
            # ship is vertical
            if point_one_x > point_two_x:
                (point_one_x, point_two_x) = (point_two_x, point_one_x)
            for x in range(point_one_x, point_two_x + 1):
                if board[x][point_one_y] != "*":
                    # print("You place the ship on top of each other")
                    print("There is already a ship at location %d, %d." % (x, point_one_y))
                    file_to_read.close()
                    print("Terminating game.")
                    sys.exit(0)
                board[x][point_one_y] = symbol
    # end of reading file
    file_to_read.close()

    # draw the AI's board at the same time
    messages = draw_ai_board(placements_info, width, height, ai_board)

    return messages
# end check_is_valid_file

def is_valid_ai_level(ai_level):
    """
    check if the user input the right AI Level
    @ai_level: the ai_level that user input
    @returns:  whether the level is valid
    """
    if ai_level in ["1", "2", "3"]:
        return True
    else:
        return False
# end is_valid_ai_level

def is_valid_user_guess_point(user_guess_string, ai_board):
    """
    check if the user guess point is valid
    @user_guess_string: user input, eg. '2 0' is valid
    @ai_board:          the AI's board to check
    @returns:           True or False
    """
    str_guess = user_guess_string.split()
    # tear it to two parts
    if len(str_guess) != 2:
        return False

    # unwrap it
    (row, col) = str_guess
    if not row.isdigit() or not col.isdigit():
        return False

    row = int(row)
    col = int(col)

    # whether the row or col is out of the board
    try:
        ai_board[row][col]
    except:
        return False

    # fire on a right place?
    if ai_board[row][col] == '*' or ai_board[row][col] != '.':
        return True

    return False
# end is_valid_user_guess_point

def get_guess_point(guess_string):
    """
    get the point based on user input string(checked)
    @guess_string: user's input string, eg. "0 1"
    @returns:      eg. (0, 1)
    """
    (row, col) = guess_string.split()
    row = int(row)
    col = int(col)
    return (row, col)
# end get_guess_point

def create_board(width, height):
    """
    create the board
    @width:   the width of the board
    @height:  the height of the board
    @returns: the created board
    """
    board = []
    for row in range(height):
        board.append(["*"] * width)
    return board
# end create_board

def print_board(board, width, height):
    """
    print the board with format
    @board:  the AI or player's board
    @width:  width of the board
    @height: height of the board
    """
    # print the first line
    # ' 0 1 2 ..'
    print(" ", end="")
    row_index = 0
    for num in range(width):
        print ((' %d' % row_index), end="")
        row_index += 1
    print("")

    #print the rest of the board
    index = 0
    for row in board:
        print(('%d ' % index) + " ".join(row))
        index += 1
# end print_board

def print_all_boards_status(ai_board_to_explore, board, width, height):
    """
    print all boards
    @ai_board_to_explore: AI's showing board
    @board:               player's board
    @width:               board's width
    @height:              board's height
    """

    # print the AI's board
    print("Scanning Board")
    print_board(ai_board_to_explore, width, height)

    # print the user's board
    print("")
    print("My Board")
    print_board(board, width, height)
    print("")
# end print_all_boards_status

def get_ship_length(placement):
    """
    get the ship length using placement
    @placement: eg. '['A', '1', '1', '2', '1']'
    @returns:   the length of the ship
    """
    point_one_x = int(placement[1])
    point_one_y = int(placement[2])
    point_two_x = int(placement[3])
    point_two_y = int(placement[4])

    if point_one_x == point_two_x:
        return abs(point_one_y - point_two_y) + 1
    else:
        return abs(point_one_x - point_two_x) + 1
# end get_ship_length

def draw_ai_board(placements_info, width, height, ai_board):
    """
    draw AI's board based on user's placements_info
    @placements_info: user's placements info
    @width:           board's width
    @height:          board's height
    @returns:         print messages list
    """
    # place the ships in order based on the ship's symbol
    placements_info = sorted(placements_info, key=lambda x: x[0])
    messages = []

    for placement in placements_info:
        direction = ''
        row = -1
        col = -1
        ship_length = get_ship_length(placement)
        symbol = placement[0]
        while not can_draw_on_the_ai_board(ai_board, symbol, direction, row, col, ship_length, width, height):
            direction = random.choice(['vert', 'horz'])
            if direction == 'horz':
                row = random.randint(0, height - 1)
                col = random.randint(0, width - ship_length)
            else:
                row = random.randint(0, height - ship_length)
                col = random.randint(0, width - 1)

        # direction, row, col is ready
        message = draw_ship_on_the_ai_board(ai_board, symbol, direction, row, col, ship_length)
        # print_board(ai_board, width, height)
        messages.append(message)

    return messages
# end draw_ai_board

def can_draw_on_the_ai_board(ai_board, symbol, direction, row, col, length, width, height):
    """
    whether AI can draw on the board with
    @symbol:   symbol of the ship, eg. 'P'
    @directon: direction of the ship eg.'horz'
    @row:      which row to draw the ship
    @col:      which col to draw the ship
    @length:   the length of the ship
    @ai_board: the board of AI
    @width:    AI board's width
    @height:   AI board's height
    @returns:  True or False
    """
    # copy the board, in case change the origin board
    # ai_board is 2D list, so has to copy like this
    temp_board = list(map(list, ai_board))

    if row < 0 and col < 0:
        return False

    if direction == 'horz':
        for i in range(col, col + length):
            if temp_board[row][i] != '*':
                return False
            else:
                temp_board[row][i] = symbol
    else:
        for i in range(row, row + length):
            if temp_board[i][col] != '*':
                return False
            else:
                temp_board[i][col] = symbol

    return True
# end can_draw_on_the_ai_board

def draw_ship_on_the_ai_board(ai_board, symbol, direction, row, col, length):
    """
    draw ship on the AI's board with
    @ai_board: the board of AI
    @symbol:   symbol of the ship
    @directon: direction of the ship
    @row:      which row to draw the ship
    @col:      which col to draw the ship
    @length:   the length of the ship
    @returns:  print messages, eg. 'Placing ship from 0,0 to 0,1.'
    """
    message = ''
    if direction == 'horz':
        for i in range(col, col + length):
            ai_board[row][i] = symbol
        message = "Placing ship from %d,%d to %d,%d." % (row, col, row, col + length - 1)
    else:
        for i in range(row, row + length):
            ai_board[i][col] = symbol
        message = "Placing ship from %d,%d to %d,%d." % (row, col, row + length - 1, col)
    return message
# end draw_ship_on_the_ai_board

def write_change_to_ai_board(ai_board_to_explore, ai_board, row, col):
    """
    write change to AI's board
    @ai_board_to_explore: AI's showing board
    @ai_board:            AI's origin board
    @row, col:            the point's location
    @return:              whether user hit a target
    """
    # get the point on the board
    # maybe '*' or symbol of the ship
    symbol = ai_board[row][col]
    if symbol == '*':
        # missed
        ai_board_to_explore[row][col] = 'O'
        print("Miss!")
        return False
    else:
        ai_board_to_explore[row][col] = 'X'
        # if user hit the point, change the origin board point to '.'
        # in case user hit it again
        # if the origin board is all '*' and '.', user wins
        sunk_symbol = ai_board[row][col]
        ai_board[row][col] = '.'
        symbols = sum(ai_board, [])
        if not sunk_symbol in symbols:
            print("You sunk my %s" % sunk_symbol)
            return True
        print("Hit!")
        return True
# def write_change_to_ai_board

def check_wins(ai_board, board, width, height, do_print = False):
    """
    check who wins the game
    @ai_board: the AI's board
    @Board:    the user's board
    @width:    board's width
    @height:   board's height
    @do_print: print the winning message? default is False
    @returns:  if somebody wins
    """
    # if ai_board is all '*' and '.', or all '.', the user wins
    ai_symbols = sum(ai_board, [])
    if set(ai_symbols) == set(['*', '.']) or set(ai_symbols) == set(['.']):
        if do_print:
            print("You win!")
        return True

    # AI wins
    user_symbols = sum(board, [])
    if set(user_symbols) == set(['*', 'X']) or set(user_symbols) == set(['X']) or set(user_symbols) == set(['*', 'X', 'O']):
        if do_print:
            print("The AI wins.")
        return True

    # no one wins
    return False
# end check_wins

def generate_ai_random_list(width, height):
    """
    create the random mode of AI's list
    eg. [[0, 0], [0, 1], [1,1]...]
    @width:   width of the board
    @height:  height of the board
    @returns: the list
    """
    ret_list = []
    for row in range(height):
        for col in range(width):
            ret_list.append([row, col])
    return ret_list
# end generate_ai_random_list

def write_change_to_user_board(point, board):
    """
    write the change to user's board
    @point:   the valid point
    @board:   the user's board
    @returns: hit or not
    """
    row = point[0]
    col = point[1]
    symbol = board[row][col]
    if symbol == '*':
        # missed
        board[row][col] = 'O'
        print("Miss!")
        return False
    else:
        # hit
        sunk_symbol = board[row][col]
        board[row][col] = 'X'
        symbols = sum(board, [])
        if not sunk_symbol in symbols:
            print("You sunk my %s" % sunk_symbol)
            return True
        print("Hit!")
        return True
# end write_change_to_user_board

def add_points_to_destory_list(destory_list, point, board, width, height):
    """
    add the point's around points into the destory list
    @destory_list: the destory list
    @point:        the point
    @board:        player's board
    @width:        board's width
    @height:       board's height
    """
    row = point[0]
    col = point[1]

    # above
    new_row = row - 1
    new_col = col
    if new_row >= 0 and board[new_row][new_col] != 'O' and board[new_row][new_col] != 'X':
        if not [new_row, new_col] in destory_list:
            destory_list.append([new_row, new_col])

    # below
    new_row = row + 1
    new_col = col
    if new_row < height and board[new_row][new_col] != 'O' and board[new_row][new_col] != 'X':
        if not [new_row, new_col] in destory_list:
            destory_list.append([new_row, new_col])

    # left
    new_row = row
    new_col = col - 1
    if new_col >= 0 and board[new_row][new_col] != 'O' and board[new_row][new_col] != 'X':
        if not [new_row, new_col] in destory_list:
            destory_list.append([new_row, new_col])

    # right
    new_row = row
    new_col = col + 1
    if new_col < width and board[new_row][new_col] != 'O' and board[new_row][new_col] != 'X':
        if not [new_row, new_col] in destory_list:
            destory_list.append([new_row, new_col])
# end add_points_to_destory_list

def cheating_ai_write_change_to_user_board(board, width, height):
    """
    level 3 AI's move
    @board:   player's board
    @width:   board's width
    @height:  board's height
    @returns: hit or not
    """

    for x in range(height):
        for y in range(width):
            symbol = board[x][y]
            if symbol != '*' and symbol != 'X':
                print("The AI fires at location (%d, %d)" % (x, y))
                write_change_to_user_board([x, y], board)
                return True
    return False
# def cheating_ai_write_change_to_user_board

def play_battleship():
    """
    play the game of battleship
    """

    # ask player to enter the seed
    seed = ''
    while not is_valid_int(seed):
        seed = input("Enter the seed: ")
    seed = int(seed)

    # ask player to enter width and height
    width = ''
    while not width.isdigit():
        width = input("Enter the width of the board: ")
    # width is a string, change it to int
    width = int(width)
    height = ''
    while not height.isdigit():
        height = input("Enter the height of the board: ")
    height = int(height)

    # ask player to enter the file name
    file_name = input("Enter the name of the file containing your ship placements: ")

    # ask player to choose AI
    ai_level = ''
    while not is_valid_ai_level(ai_level):
        ai_level = input("Choose your AI.\n1. Random\n2. Smart\n3. Cheater\n Your choice: ")
    ai_level = int(ai_level)

    # print the AI's board
    ai_board_to_explore = create_board(width, height)

    # 1. Seed the random number generator with the provided seed
    random.seed(seed)

    # 2. Construct the user's board
    board = create_board(width, height)
    # 3. Construct the AI's board
    ai_board = create_board(width, height)

    # print placing ship messages
    # eg. Placing ship from 2,0 to 3,0.
    messages = check_is_valid_file(file_name, board, width, height, ai_board)
    for msg in messages:
        print(msg)

    # who to first
    who_first = random.randint(0, 1)

    # list for level 1 AI
    if ai_level == 1:
        random_ai_list = generate_ai_random_list(width, height)
    if ai_level == 2:
        # list for hunt mode
        random_ai_list = generate_ai_random_list(width, height)
        destory_list = []

    if who_first == 0:
        print_all_boards_status(ai_board_to_explore, board, width, height)

    while not check_wins(ai_board, board, width, height, do_print=True):
        if who_first == 0:
            # player goes
            user_guess_point = ''
            while not is_valid_user_guess_point(user_guess_point, ai_board):
                try:
                    user_guess_point = input("Enter row and column to fire on separated by a space: ")
                except:
                    # EOFError
                    pass

            # get the point(two ints)
            (guess_row, guess_col) = get_guess_point(user_guess_point)
            # write the change to the AI's board
            write_change_to_ai_board(ai_board_to_explore, ai_board, guess_row, guess_col)

            if check_wins(ai_board, board, width, height) == True:
                print_all_boards_status(ai_board_to_explore, board, width, height)
            who_first = 1
        else:
            # AI goes
            if ai_level == 1:
                # random search
                point = random.choice(random_ai_list)
                random_ai_list.remove(point)
                print("The AI fires at location (%d, %d)" % (point[0], point[1]))
                # make changes to the board
                write_change_to_user_board(point, board)
            elif ai_level == 2:
                # get a point in the hunter list
                if len(destory_list) > 0:
                    # destory mode
                    point = destory_list[0]
                else:
                    # hunt mode
                    point = random.choice(random_ai_list)

                print("The AI fires at location (%d, %d)" % (point[0], point[1]))
                # remove point in two lists
                if point in random_ai_list:
                    random_ai_list.remove(point)
                if point in destory_list:
                    destory_list.remove(point)

                if write_change_to_user_board(point, board) == True:
                    # AI hits the ship, add points to destory_list
                    add_points_to_destory_list(destory_list, point, board, width, height)
            else:
                # ai_level == 3:
                cheating_ai_write_change_to_user_board(board, width, height)
            print_all_boards_status(ai_board_to_explore, board, width, height)

            who_first = 0
    # end while
# end play_battleship


if __name__ == '__main__':
    play_battleship()

以上是关于python battleship.py的主要内容,如果未能解决你的问题,请参考以下文章

001--python全栈--基础知识--python安装

Python代写,Python作业代写,代写Python,代做Python

Python开发

Python,python,python

Python 介绍

Python学习之认识python