I am somewhat new to Python, and this is a homework question, so I would appreciate no answers, just advice to help me understand. I am writing a game program that plays two different strategies against each other - a greedy strategy and a zoom-in strategy, which I have written as function. I have a game function that needs to pass in my greedy and zoom-in functions, as well as a game board. I need to be able to have either strategy function go first. So far I can only get it to where my greedy strategy goes first.
def game(P1,P2,board):
P1 = 0
P2 = 0
for x in range(len(board)):
if x%2 == 0:
move = greedy(board)
P1 += board[move]
board.remove(board[move])
else:
move = zoomin(board)
P2 += board[move]
board.remove(board[move])
if P1 > P2:
return 1
elif P1 == P2:
return 0.5
else:
return 0
This strategy always assumes that P1 is the greedy function, but I need to be able to play either first. I thought I could pass in the functions, so my call would be
game(greedy,zoomin,board)
but I am not sure how to actually implement it so that it can recognize who is playing first.
Thank you in advance for your help!
EDIT:
Here are my greedy and zoomin functions:
def greedy(board):
if board[0] > board[len(board)-1]:
#returns position of first item
return 0
elif board[len(board)-1] > board[0]:
#returns position of last item
return len(board)-1
else:
#if board[-1] == board[0]
return 0
def zoomin(board):
if len(board)%2 == 0:
evens = 0
odds = 0
for x in range(len(board)):
if x%2 ==0:
evens += board[x]
else:
odds += board[x]
if evens > odds:
return 0
else:
return len(board)-1
else:
#choose the larger value (greedy)
if board[0] < board[len(board)-1]:
return len(board)-1
else:
return 0
This is not a direct answer to your question (since senshin already answered it), but I wanted to point out that you can decrease your code duplication by using arrays instead. For instance, like this:
def game(players, board):
scores = [0] * len(players)
while i in range(len(board))
p = i % len(players)
move = players[p](board)
scores[p] += board[move]
del board[move] # <-- This is also a faster and more fail-safe version of your "board.remove(board[move])"
return scores
You can then call this function as game([greedy, zoomin], board). Also note how it extends to an arbitrary number of players, although that may not actually be useful for you. :)
You will want to rewrite your game function slightly. Notice that your game function accepts P1 and P2, but you don't do anything with them - you immediately assign 0 to both of them.
The correct way to approach this is to have your game function accept two strategies, which can be greedy or zoomin, or whatever else you might come up with later.
def game(strategy1, strategy2, board):
You will also need to replace the explicit calls to greedy and zoomin in the function body (e.g. move = greedy(board)) with calls to the strategies passed into your function instead - something like move = strategy1(board).
Then, in order to have greedy play first and zoomin play second, you could call:
game(greedy, zoomin, board)
Or if you wanted zoomin first and greedy second, you could call:
game(zoomin, greedy, board)
As you can see, the order of play is determined by the order in which you pass the two strategies into your function. Let me know if this needs clarification.
Related
Given 1 to 100 numbers, for multiples of 3 it should print "he" ,for multiples of 5 it should print "llo" ,for both multiples of 3 and 5 it should print "hello".
This is what I have:
for i in range (1,100):
if(i%3==0):
print("he")
elif(i%5==0):
print("llo")
elif(i%3==0 and i%5==0):
print("hello")
How would I do this recursively?
How about the code below?
def find_multiples(current, last_num=100):
# Base Case
if current > last_num:
return
result = ""
if current % 3 == 0:
result += "he"
if current % 5 == 0:
result += "llo"
if result:
print(f"{current}: {result}")
find_multiples(current+1, last_num)
find_multiples(1)
Base case is if current reaches last_num or the maximum number you'd like to check.
Here is a general outline for doing simple recursive things in python:
BASE_CASE = 1 #TODO
def f(current_case):
if current_case == BASE_CASE:
return #TODO: program logic here
new_case = current_case - 2 #TODO: program logic here ("decrement" the current_case somehow)
#TODO: even more program logic here
return f(new_case) + 1 #TODO: program logic here
Of course, this doesn't handle all possible recursive programs. However, it fits your case, and many others. You would call f(100), 100 would be current_value, you check to see if you've gotten to the bottom yet, and if so, return the appropriate value up the call stack. If not, you create a new case, which, in your case, is the "decrement" logic normally handled by the "loop" construct. You then do things for the current case, and then call the function again on the new case. This repeated function calling is what makes it "recursive". If you don't have an "if then" at the beginning of the function to handle the base case, and somewhere in the function recall the function on a "smaller" value, you're probably going to have a bad time with recursion.
This recursive function prints multiples of a number! hope it helps
def multi(n,x):
if x == 12:
print(n*x)
else :
print(n*x,end =",")
multi(n,x+1)
print(multi(4,1));
I am trying to finish 1 exercise but i cannot find a solution myself.
I get a number and function should use recursion to find a value:
if n == 1: return 1
elif n != 1: fun(n-1) + n
but i want to provide to my function 2 values, starting point and finishing point and my function finds all values in range(starting point, finishing point).
Define your function with two parameters. One of them gets idecremented when you make the recursive call, the other is kept the same:
def sumRange(start, end):
if start > end:
return None # or could signal an error
elif start == end:
return start
else:
return sumRange(start, end-1) + end
Don't forget that when you make the recursive call, you have to return the result.
Hopefully I can explain this correctly without having to paste a whole wall of code in.
I have a list [0:100]. I need to find the lowest sufficient value in the list that will return a True in another function.
The trick is that I need this to be done fast! so far some of the data has taken over 65 seconds to process, due to the latter function iterating over the specific index in the list over 1000 times.
def search(list,grid):
print(list)
if len(list) <= 2:
return list[0]
else:
p = len(list)//2
print(p)
print(list[p])
if simulation(grid,list[p]) == 'lose':
return search(list[p:len(list)-1],grid)
elif simulation (grid,list[p]) == 'win':
return search(list[0:p],grid)
For a certain input I need the function to return a result in less than 10 seconds. Is there anyway that I can precisely find the value I'm looking for without having to pass every single values from 0 to 100 to the function that relies on the list?
It may not be sufficient, to reach your goal, but one obvious improvement is to avoid recalculating the simulation for the same values, in case it is not a lose.
Removing all print output will speed things up too.
def search(seq, grid):
if len(seq) <= 2:
return seq[0]
p = len(seq)//2
sim_result = simulation(grid, seq[p])
if sim_result == 'lose':
return search(seq[p: len(seq)-1], grid)
elif sim_result == 'win':
return search(seq[0: p], grid)
You will probably have to look at how the simulation is run to improve further.
I’m trying to build a program that plays draughts/checkers. At the moment I’m trying to make the function, that allows the computer to make and evaluate moves. My idea is to have the computer look at all it’s own possible moves and for each of these moves, look at the possible opponents moves and then for each of these moves, again look at it’s own possible moves.
With each ply it will evaluate if the move is good or bad for the player and assign points, at the end it picks the moves with the highest points.
So far I have managed to get a version of this working, but involves a lot of nested for loops. The code is a mess and not very readable at the moment, but this is a simple model of the same concept. Instead of evaluating and producing more lists, it just multiplies by two for the new list.
counter = 0
for x in list:
counter += 1
list_2 = [x * 2 for x in list]
print 'list_2', list_2, counter
for x in list_2:
counter += 1
list_3 = [x * 2 for x in list_2]
print 'list_3',list_3, counter
for x in list_3:
counter += 1
list_4 = [x * 2 for x in list_3]
print 'list_4', list_4, counter
If I run this code, I get what I want, except that I can't easily control the depth of the search without copying in more for loops. I thought recursion might be a way of doing this, but I can’t figure out how to stop the recursion after x levels of search depth.
Is there a better way of getting the same output form the code above, while getting rid of all the for loops? If I can get that to work, I think I can do the rest myself.
Here's an equivalent function that uses recursion. It controls the recursion with two parameters which track the current depth and maximum depth. If current depth exceeds the maximum depth it will return immediately thus stopping the recursion:
def evaluate(l, max_depth, cur_depth=0, counter=0):
if cur_depth > max_depth:
return counter
for x in l:
counter += 1
l2 = [x * 2 for x in l]
print cur_depth, l2, counter
counter = evaluate(l2, max_depth, cur_depth + 1, counter)
return counter
If called with max_depth=2 it will produce the same output except that instead of variable name the current depth is printed.
I thought recursion might be a way of doing this, but I can’t figure out how to stop the recursion after x levels of search depth.
Your intuition is correct, and a simple a way of doing this would be to have an incrementing number passed to each level. When the recursion gets the maximum value then the recursion is completed. A trivial example is below to demonstrate.
def countup(i=0):
print(i)
if i==MAX_COUNT: return
countup(i+1)
For your algorithm, you need a value to represent the board evaluation. For instance in the range [-1,1]. Player A could be said to be winning if the evaluation is -1 and Player B is winning if the evaluation is 1 for example. A recursive algorithm could be as follows.
def evaulate(board, player, depth=0):
if depth==MAX_DEPTH: return hueristicEvaluation(board)
bestMove = None
if player==PLAYER_A:
val=999 # some large value
for move in get_moves():
newboard = board.makeMove(move)
eval, _ = evaluate(newboard, PLAYER_B, depth+1)
if eval < val:
bestMove = move
val = eval
elif player==PLAYER_B:
val=-999 # some large negative value
for move in get_moves():
newboard = board.makeMove(move)
eval, _ = evaluate(newboard, PLAYER_A, depth+1)
if eval > val:
bestMove = move
val = eval
return val, bestMove
This is abstract, but the idea is there. Adjust depending on how your are representing the board or the players. The function hueristicEvaluation could be something as simple as counting the pieces on the board for each player and how close they are to the other side. Remember that this function needs to return a number between [-1,1]
Edge cases to consider, which I didn't take into account:
If all moves are winning and/or losing
If the are NO moves in the position, for example if your pieces are all blocked by your opponent's pieces
Many improvements exist to a simple search like this. Read if you're interested :)
For checkers, perhaps Memoization would speed things up a lot. I'm not sure, but I'd think it would be especially in the beginning. See python's way of doing this.
Pruning
Alpha-beta pruning
Branch and bound
I've just started exploring the wonders of programming. I'm trying to write a code to identify numeric palindromes. Just looking at numbers and not texts. I'm trying to learn to use recursion here. But I'm just not getting anywhere and I can't figure out what's wrong with it.
My idea was to check first string vs the last, then delete these two if they match, and repeat. Eventually there'll be nothing left (implying it is a palindrome) or there will be a couple that doesn't match (implying the reverse).
I know there are better codes to finding palindromes in but I just wanted to try my hand at recursion.
So what's wrong?
def f(n):
global li
li=list(str(n))
if (len(li)==(1 or 0)):
return True
elif li[len(li)-1]==li[0]:
del li[0]
del li[len(li)-1]
if len(li)==0:
return True
if len(li)>0:
global x
x=''.join(li)
str(x)
f(x)
else:
return False
Thanks in advance!
A few comments
Why are x and li globals? In recursion, all variables should be local.
Why are you converting back and forth between str and list? You can subscript both of them
You need to return the result of your recursive call: return f(x)
Try these suggestions, and see how it works out.
Before looking into it too much, if (len(li)==(1 or 0)): doesn't do what you're expecting it to do. (1 or 0) will always evaluate to 1.
You probably want:
if len(li) in (1, 0):
There are a couple of problems with your solution. Let me analyse them line by line.
You don't need global statements if you don't intend to change variables outside of function scope. Thus, I removed two lines with global from your code.
li=list(str(n)): casting a string to a list is unnecessary, as a string in Python has a similar interface to an immutable list. So a simple li = str(n) will suffice.
if (len(li)==(1 or 0)):: although it looks OK, it is in fact an incorrect way to compare a value to a few other values. The or operator returns the first "true" value from its left or right operand, so in this case it always returns 1. Instead, you can use the in operator, which checks whether the left operand is an element of a right operand. If we make the right operand a tuple (1, 0), all will be well. Furthermore, you don't need parentheses around the if statement. You should write: if len(li) in (1, 0):
elif li[len(li)-1]==li[0]: is fine, but we can write this shorter in Python, because it supports negative list indexing: elif li[-1] == li[0]:
Because we don't use lists (mutable sequences) because of point 2., we can't do del li[0] on them. And anyway, removing the first element of a list is very inefficient in Python (the whole list must be copied). From the very same reason, we can't do del li[len(li)-1]. Instead, we can use the "splicing" operator to extract a substring from the string: li = li[1:-1]
if len(li)==0: is unnecessary long. In Python, empty strings and lists resolve to False if tested by an if. So you can write if not li:
if len(li)>0:: You don't have to check again if li is not empty -- you checked it in point 6. So a simple else: would suffice. Or even better, remove this line completely and unindent the rest of the function, because the body of the if in 6. contains a return. So if we didn't enter the if, we are in the else without writing it at all.
x=''.join(li): We don't need to convert our string to a string, because of the decision made in 2. Remove this line.
str(x): This line didn't do anything useful in your code, because str() doesn't modify its argument in place, but returns a new value (so x = str(x) would have more sense). You can also remove it.
f(x): This is a valid way to call a recursive function in Python, but you have to do something with its value. Return it perhaps? We'll change it to: return f(li) (as we don't have an x variable any more).
We end up with the following code:
def f(n):
li = str(n)
if len(li) in (1, 0):
return True
elif li[-1] == li[0]:
li = li[1:-1]
if not li:
return True
return f(li)
else:
return False
It's almost what we need, but still a little refinement can be made. If you look at the lines if not li: return True, you'll see that they are not necessary. If we remove them, then f will be called with an empty string as the argument, len(li) will equal 0 and True will be returned anyway. So we'll go ahead and remove these lines:
def f(n):
li = str(n)
if len(li) in (1, 0):
return True
elif li[-1] == li[0]:
li = li[1:-1]
return f(li)
else:
return False
And that's it! Good luck on your way to becoming a successful programmer!
Split the whole show out into a list, then just:
def fun(yourList):
if yourList.pop(0) == yourList.pop(-1):
if len(yourList) < 2:
return True # We're a palindrome
else:
return fun(yourList)
else:
return False # We're not a palindrome
print "1234321"
print fun(list("1234321")) # True
print "6234321"
print fun(list("6234321")) # False
def palindrome(n):
return n == n[::-1]
It's hard to tell what you intend to do from your code, but I wrote a simpler (also recursive) example that might make it easier for you to understand:
def is_palindrome(num):
s = str(num)
if s[0] != s[-1]:
return False
elif not s[1:-1]:
return True
else:
return is_palindrome(int(s[1:-1]))
number = int(raw_input("Enter a number: "))
rev = 0
neg = number
original = number
if (number < 0):
number = number * -1
else:
number = number
while ( number > 0 ):
k = number % 10
number = number / 10
rev = k + ( rev * 10 )
if (number < 1):
break
if ( neg < 0 ):
rev = ( rev * -1)
else:
rev = (rev)
if ( rev == original):
print "The number you entered is a palindrome number"
else:
print "The number you entered is not a palindrome number"
This code even works for the negative numbers i am new to programming in case of any errors
dont mind.