0

I am currently working on a Battleships project in Python where we have been given the task of creating our own strategy for the game which has a board in the shape of an L (removing the upper right quadrant). My strategy, when choosing the moves, was going to be like a checkerboard effect where when it hit a ship it would check the adjacent squares. The problem I have is that when the function is returned it no longer keeps the values for the row and column number where the hit was last turn.

I am wondering if there is a way to record the row and column variables for when the function is run again for the next move.

Here is the section of the code containing the variables I want to recall the next time the code is run:

def chooseMove():

    global playerBoard, opponentBoard

    row = int()
    col = int()

    if (opponentBoard[row][col] == const.HIT):
    row = row - 1
        if (opponentBoard[row][col] == const.MISSED) or (opponentBoard[row][col] == const.HIT) or (opponentBoard[row] < 0):
        row = row + 1
            if (opponentBoard[row][col] == const.MISSED) or (opponentBoard[row][col] == const.HIT) or ((opponentBoard[row] > 5) and (opponentBoard[col] < 6)):
            col = col - 1
                if (opponentBoard[row][col] == const.MISSED) or (opponentBoard[row][col] == const.HIT) or (opponentBoard[col] < 0):
                col = col + 1
                    if (opponentBoard[row][col] == const.MISSED) or (opponentBoard[row][col] == const.HIT) or ((opponentBoard[row] > 5) and (opponentBoard[col] < 6)):
                        while (opponentBoard[row][col] == const.HIT) or (opponentBoard[row][col] == const.MISSED) or ((row + col) % 2 == 1):
                            row = randint(0,len(opponentBoard)-1)
                            col = randint(0,len(opponentBoard[row])-1)
                        else:
                            return row, col
                    else:
                        return row, col 
                else:
                    return row, col
            else:
                return row, col
        else:
            return row, col
    else: 
        while (opponentBoard[row][col] == const.HIT) or (opponentBoard[row][col] == const.MISSED) or ((row + col) % 2 == 1):
            row = randint(0,len(opponentBoard)-1)
            col = randint(0,len(opponentBoard[row])-1)
        else:
            return row, col
Ffisegydd
  • 51,807
  • 15
  • 147
  • 125
ThomasB2685
  • 17
  • 1
  • 4
  • 1
    Any reason you don't want to store the last couple moves in a list and then pass it to the chooseMove() function as an argument? – derricw Sep 25 '14 at 16:20
  • Would I store the values for the row and col before each of the returns? Would python remember what has been stored in the list after it has been returned and then ran through again? – ThomasB2685 Sep 25 '14 at 17:26

1 Answers1

0

You could add a parameters to the chooseMove() function that contains the positions you have already tested. Or you could convert your code into a method of a class, and use a class instance that remembers the positions, and let go of the global variables. Or you could use a closure to store state for your method:

#!/usr/bin/env python
def make_function(x):
    my_var = [x]
    def my_function(a):
            print a + my_var[0]
            my_var[0] += 1
    return my_function

fct = make_function(15)
for i in xrange(10):
    fct(10)

Output:

25
26
27
28
29
30
31
32
33
34

As this example demonstrates, the returned function keeps internal state. See closures in Python. This way you avoid writing a custom class or passing around data sets with your move data. This hides your implementation to the outside world and nobody from outside has to care for an aditional parameter.

You could use any other mutable object like a dictionary or a custom class instead of the list. In Python3 you can use anything together with the nonlocal keyword, but with Python 2.x this is not possible, unfortunately.

Community
  • 1
  • 1
hochl
  • 12,524
  • 10
  • 53
  • 87
  • Do you really mean "class method" (as defined using @classmethod)? Sounds more like you really mean method. – Anton Sep 25 '14 at 16:30
  • Ah yeah, sorry bad wording (not a native speaker). – hochl Sep 25 '14 at 16:31
  • So would I set up the a new function with a list containing the previous move before the chooseMove(): function and then append the last move onto that list before returning the row and col? – ThomasB2685 Sep 25 '14 at 17:30
  • You put whatever you want inside the list, for example your last move(s) or whatever you want to keep persistently, then write `def chooseMove(): my_var = [ ... ] ; def my_function( ... ): ... return my_function` and make use of the list inside of `my_function`, which contains the real code of your `chooseMove()` function. `chooseMove()` contains the persistent data and wraps the function `my_function` that contains the implementation. – hochl Sep 25 '14 at 17:48
  • You could use any other mutable object like a dictionary or a custom class instead of the list. In Python3 you can use anything together with the `nonlocal` keyword, with Python 2.x this is not possible, unfortunately – hochl Sep 25 '14 at 17:52
  • I have set it up like you have said with the chooseMove() housing the list called lastHit = [0, 0]; and the new function called lastMove(row, col): with the code in. Inside the new function I set the values of row and col = to the lastHit[0] and [1] respectively. Now when I run the code, and it goes to choose the move, it is giving a NoneType object is not iterable error for the values of row and col? – ThomasB2685 Sep 25 '14 at 19:49
  • I'm not quite sure what you mean, can you show the whole code? (for example on pastebin?) – hochl Sep 25 '14 at 22:11
  • Your last line is misaligned, you should indent it to the same level as the `lastHist = [ ... ]` statement on line two. Oh, and change line 2 to `lastHit = [1, 1]`. – hochl Sep 26 '14 at 10:26