I'd like to the first value that outputs True for my function. I currently have a search that works fine, but I think is still a bit inefficient. Could anyone suggest a better binary search? My code is below, simplified.
guess = 2
limits = [2, 2**35] #The search area
while True:
if myFunction(guess) == False:
limits[0] = max(limits[0], guess) #Limit the search area
guess *= 2
else:
limits[1] = min(limits[1], guess) #Limit the search area
guess = int((limits[0] + limits[1])/2) #The guess is the midpoint of the search area
if myFunction(guess) == True and myFunction(guess-1) == False:
return guess
This is the classical problem of finding a level-crossing of a monotonically increasing or decreasing function. As you guessed, it is solvable by binary search. Your code has some bugs, which is not surprising:
Although the idea is simple, implementing binary search correctly requires attention to some subtleties about its exit conditions and midpoint calculation.
So, you should avoid writing your own binary search when possible. Fortunately, Python offers a library module bisect which can do the job for you.
from bisect import bisect_left
MIN = 2
MAX = 2**35
def search(f):
# Finds the first position of `True` in `f`
return bisect_left(f, True, lo=MIN, hi=MAX + 1)
Don't be confused by the fact that bisect only works with indexable objects: there is no need to create a list with 2**35 elements. You can use a generator object instead using the __getitem__ syntax. To do that, encapsulate your function in a class and define the getter method that would return False for all argument values on the left side of the point of interest and True otherwise.
def myFunction1(index):
return index >= 1456
def myFunction2(index):
return index >= 2
def myFunction3(index):
return index >= MAX - 1
class F:
def __init__(self, f):
self.f = f
def __getitem__(self, index):
return self.f(index)
# testing code
print(search(F(myFunction1))) # prints 1456
print(search(F(myFunction2))) # prints 2
print(search(F(myFunction3))) # prints MAX - 1
Related
The problem is formulated as follows:
Write a recursive function that, given a string, checks if the string
is formed by two halves equal to each other (i.e. s = s1 + s2, with s1
= s2), imposing the constraint that the equality operator == can only be applied to strings of length ≤1. If the length of the string is
odd, return an error.
I wrote this code in Python 2.7 that is correct (it gives me the right answer every time) but does not enter that recursive loop at all. So can I omit that call here?
def recursiveHalfString(s):
##param s: string
##return bool
if (len(s))%2==0: #verify if the rest of the division by 2 = 0 (even number)
if len(s)<=1: # case in which I can use the == operator
if s[0]==s[1]:
return True
else:
return False
if len(s)>1:
if s[0:len(s)/2] != s[len(s)/2:len(s)]: # here I used != instead of ==
if s!=0:
return False
else:
return recursiveHalfString(s[0:(len(s)/2)-1]+s[(len(s)/2)+1:len(s)]) # broken call
return True
else:
return "Error: odd string"
The expected results are True if the string is like "abbaabba"
or False when it's like anything else not similat to the pattern ("wordword")
This is a much simplified recursive version that actually uses the single char comparison to reduce the problem size:
def rhs(s):
half, rest = divmod(len(s), 2)
if rest: # odd length
raise ValueError # return 'error'
if half == 0: # simplest base case: empty string
return True
return s[0] == s[half] and rhs(s[1:half] + s[half+1:])
It has to be said though that, algorithmically, this problem does not lend itself well to a recursive approach, given the constraints.
Here is another recursive solution. A good rule of thumb when taking a recursive approach is to first think about your base case.
def recursiveHalfString(s):
# base case, if string is empty
if s == '':
return True
if (len(s))%2==0:
if s[0] != s[(len(s)/2)]:
return False
else:
left = s[1:len(s)/2] # the left half of the string without first char
right = s[(len(s)/2)+1: len(s)] # the right half without first char
return recursiveHalfString(left + right)
else:
return "Error: odd string"
print(recursiveHalfString('abbaabba')) # True
print(recursiveHalfString('fail')) # False
print(recursiveHalfString('oddstring')) # Error: odd string
This function will split the string into two halves, compare the first characters and recursively call itself with the two halves concatenated together without the leading characters.
However like stated in another answer, recursion is not necessarily an efficient solution in this case. This approach creates a lot of new strings and is in no way an optimal way to do this. It is for demonstration purposes only.
Another recursive solution that doesn't involve creating a bunch of new strings might look like:
def recursiveHalfString(s, offset=0):
half, odd = divmod(len(s), 2)
assert(not odd)
if not s or offset > half:
return True
if s[offset] != s[half + offset]:
return False
return recursiveHalfString(s, offset + 1)
However, as #schwobaseggl suggested, a recursive approach here is a bit clunkier than a simple iterative approach:
def recursiveHalfString(s, offset=0):
half, odd = divmod(len(s), 2)
assert(not odd)
for offset in range(half):
if s[offset] != s[half + offset]:
return False
return True
I'm trying to write a recursive function in python, but instead of returning an integer type it returns a nonetype. I know there are other questions smiliar to this but not a single solution there worked for me.
Here is the code:
class t:
def search(self, globina, board):
board.legals = board.legal()
bestMove = 0
if(globina == 0):
return board.evaluation()
elif board.turn == False:
bestMove = -9999
for i in range(0, len(board.legals)):
board.move(board.legals[i])
board.display()
bestMove = max(bestMove, self.search(globina-1, board))
board.undo()
return bestMove
else:
bestMove = 9999
for i in range(0, len(board.legals)):
board.move(board.legals[i])
board.display()
bestMove = min(bestMove, self.search(globina-1, board))
board.undo()
return bestMove
z = t()
z.search(globina, board)
Your recursive method (as it appears in edited question) is doing the right thing, since it uses return in all of its cases.
That means that the None value must not be due to the recursive function itself, but rather it's a value being returned in the base case somewhere. For your function, that means board.evaluation() returns None at least some of the time.
In Python 3, I'd expect that to cause an exception in any of the recursive cases, as min and max will choke on a None value (since None isn't comparable to anything, including itself). In Python 2 however, all objects are comparable, though there may not be any particular meaning to comparisons between unlike types. The default behavior is to compare class names alphabetically (so all int and float instances are less than all str instances, which are less than all tuples), though if I recall correctly, None compares as less than all other values.
I'm trying to build a min-max algorithm for a Tic-Tac-Toe that never lose...
I try to build it from reading few sources:
http://neverstopbuilding.com/minimax
http://www.geeksforgeeks.org/minimax-algorithm-in-game-theory-set-3-tic-tac-toe-ai-finding-optimal-move/ (I built something very similar to this one).
Here is the code:
class tree:
def find_best_move(self,board,depth,myTurn,sign):
"""
:param board:
:return:
"""
if (board.empty==[]): return None
best_move=-(2**(board.s**2))
m=board.empty[0]
for move in board.empty:
b=copy.deepcopy(board)
b.ins(move,sign)
if (self.is_win(b,sign) or self.is_win(b,xo.opp_sign(sign))):
return move
curr_move=self.minimax(b,depth,myTurn,sign)
if (curr_move > best_move):
best_move = curr_move
m=move
print(curr_move,best_move,m)
return m #This should be the right move to do....
# *****************************************************************************************************#
def minimax(self,board,depth,myTurn,sign):
"""
:param depth:
:param myTurn:
:return:
"""
#print(depth,end='\n')
if (self.is_win(board,sign)):
#print("I win!")
return (board.s**2+1) - depth
elif (self.is_win(board,xo.opp_sign(sign))):
#print("You win!")
return -(board.s**2+1) + depth
elif (board.is_full()):
return 0
if (myTurn):
bestVal=-(2**700)
for move in board.empty: #empty - the empty squares at the board
b = copy.deepcopy(board)
b.ins(move, sign)
value=self.minimax(b,depth+1,not myTurn, xo.opp_sign(sign))
#xo.opp_sign(sign) - if function for the opposite sign: x=>o and o=>x
bestVal = max([bestVal,value])
return bestVal
else:
bestVal = (2**700)
for move in board.empty:
b = copy.deepcopy(board)
b.ins(move, xo.opp_sign(sign))
value = self.minimax(b, depth + 1, not myTurn, xo.opp_sign(sign))
#print("opp val: ",value)
bestVal = min([bestVal, value])
return bestVal
# *****************************************************************************************************#
def is_win(self,board, sign):
"""
The function gets a board and a sign.
:param board: The board.
:param sign: The sign (There are only two options: x/o).
:return: True if sign "wins" the board, i.e. some row or col or diag are all with then sing. Else return False.
"""
temp=board.s
wins = [] # The options to win at the game.
for i in range(1, temp + 1):
wins.append(board.get_col(i))
wins.append(board.get_row(i))
wins.append(board.get_diag1())
wins.append(board.get_diag2())
for i in wins:
if (self.is_same(i, sign)):
return True
return False
# *****************************************************************************************************#
def is_same(self, l, sign):
"""
The function get a list l and returns if ALL the list have the same sign.
:param l: The list.
:param sign: The sign.
:return: True or false
"""
for i in l:
if (i != sign):
return False
return True
If something is wrong at my code please tell me!
But, I always can beat this - I just need to make a "fork"
.e.g.: (I'm x, the algorithm is o)
xx-
xo-
-o-
And I win...
There is algorithm for making a tree that can block forks?
You have three errors.
1. In your minimax method the sign is swapped one time too many
You swap the sign in the else block -- for the case where myTurn is False -- but you shouldn't. You already swap the sign with each recursive call. Because of this bug, you always puts the same sign on the board during your minimax search, never the opposite one. Obviously you therefore miss all the threats of the opponent.
So change:
else:
bestVal = (2**700)
for move in board.empty:
b = copy.deepcopy(board)
b.ins(move, error xo.opp_sign(sign)) # <-- bug
to:
else:
bestVal = (2**700)
for move in board.empty:
b = copy.deepcopy(board)
b.ins(move, sign) # <-- corrected
2. In find_best_move you should swap the move as you call minimax
And a similar bug occurs in find_best_move. As you go through each move, you must swap the sign when calling minimax in the new board, otherwise you let the same player play twice.
So change this:
for move in board.empty:
b=copy.deepcopy(board)
b.ins(move,sign)
if (self.is_win(b,sign) or self.is_win(b,xo.opp_sign(sign))):
return move
curr_move=self.minimax(b,depth,myTurn,sign) # <-- bug
to:
for move in board.empty:
b=copy.deepcopy(board)
b.ins(move,sign)
if (self.is_win(b,sign) or self.is_win(b,xo.opp_sign(sign))):
return move
curr_move=self.minimax(b,depth,not myTurn,xo.opp_sign(sign)) # <-- corrected
Note that the second condition should not be necessary: if you are the one who just moved, it is not logical that the other should come in a winning position.
3. In minimax you don't consider the value of myTurn when there is win
Although you consider the value of myTurn to determine whether to minimise or maximise, you don't perform this operation when checking for a win.
You currently have this:
if (self.is_win(board,sign)):
#print("I win!")
return (board.s**2+1) - depth
elif (self.is_win(board,xo.opp_sign(sign))):
#print("You win!")
return -(board.s**2+1) + depth
elif (board.is_full()):
return 0
First of all, the first if condition should not be true ever, because the most recent move was for the opposite sign, so that could never lead to a win for sign.
But to the issue: the second if does not look to myTurn to determine whether the return value should be negative or positive. It should do so to be consistent. So change the above code to this:
if self.is_win(board,xo.opp_sign(sign)):
if myTurn:
return -(board.s**2+1) + depth
else:
return (board.s**2+1) - depth
elif board.is_full():
return 0
How to call find_best_move
Finally, the above works if you always call find_best_move with the myTurn argument as True, because find_best_move maximises the result as can be seen from if (curr_move > best_move). So, to avoid that you call it with False, you would better remove this argument and pass False to minimax. So:
def find_best_move(self,board,depth,sign): # <-- myTurn removed as argument
# ... etc ...
curr_move=self.minimax(b,depth,False,xo.opp_sign(sign)) # pass False
This way, the argument myTurn indicates whether the turn is to the same player as the player for which find_best_move was called.
Working Solution
With minimal code added to make it work (Board and XO classes added), the program can be seen to run on repl.it.
Note that this algorithm is not optimal. It is just brute force. You could look into storing results of previously evaluated positions, doing alpha-beta pruning, etc...
I am pretty new so I apologize if I make any errors in posting here... I did a search but didn't come up with much that would help me. I am writing a miniMax algorithm for a variation on Tic Tac Toe. This variation allows either player to put an X or an O anywhere on the board. I am having trouble with the recursion and was hoping I could get a bit of guidance.
class TicTacToeBoard:
def __init__(self, initGameBoard):
#initGameBoard is a string
self.board = initGameBoard
def getEmptySpaces(self):
return self.board.count("-")
def markX(self, index):
self.board = self.board[:index] + "x" + self.board[index+1:]
def markO(self, index):
self.board = self.board[:index] + "o" + self.board[index+1:]
def endGame(self):
#determines if someone has won
endGameStates = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]
for x in range(len(endGameStates)):
trySlice = self.board[endGameStates[x][0]] + self.board[endGameStates[x][1]] + \
self.board[endGameStates[x][2]]
if trySlice[0] == trySlice[1] == trySlice[2] and "-" not in trySlice:
return True
return False
def draw(self):
#determines if there has been a draw
if "-" not in self.board:
endGameStates = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]
for x in range(len(endGameStates)):
trySlice = self.board[endGameStates[x][0]] + self.board[endGameStates[x][1]] + \
self.board[endGameStates[x][2]]
if trySlice[0] == trySlice[1] == trySlice[2] and "-" not in trySlice:
return False
return True
else:
return False
def __str__(self):
boardStr = ""
for char in self.board:
boardStr += char
return boardStr
Above is my board class. I'm just using strings, not doing anything too fancy. I'm also using a very simple Node class that just stores data (though I suppose I might be able to just use strings too I guess...)
from tic_tac_toe_board import TicTacToeBoard
from node import Node
nodeQueue = []
def fitnessFunction(gameBoard):
#only runs if end game or if all full
if gameBoard.draw():
return 0
else:
emptySpaces = gameBoard.getEmptySpaces()
if emptySpaces %2 == 0:
#max won
return (emptySpaces + 1) *1
else:
#max lost
return (emptySpaces + 1) *-1
def miniMax(gameBoard):
if gameBoard.endGame() or if "-" not in gameBoard:
#end game checks for winner, second clause checks for full/draw
return fitnessFunction(gameBoard)
else:
emptyIndexes = [] #keeps track of which indexes are empty
count = 0
for char in gameBoard:
if char == "-":
emptyIndexes.append(count)
count +=1
if len(emptyIndexes) %2 != 0:
#max's turn
for index in emptyIndexes:
childNode = Node(gameBoard.markX(index))
nodeQueue.append(childNode)
childNode = Node(gameBoard.markO(index))
nodeQueue.append(childNode)
return miniMax()
The fitnessFunction returns a score based on the number of empty spaces left. I'm having trouble with my recursive miniMax method. What I need to do is check for the base cases (either player winning, or a draw) and if those base cases are not true, I figure out whose move it is based on the number of empty spaces left. I think I've gotten that far, but I don't know what to do next (the recursive part). I also need to be able to get the min or max of children, depending on whose turn it is. I guess I am lost with the recursion. I'm new to CS and haven't touched much on it. Any hints would be greatly appreciated! :)
If you are looking for a mini-max algorithm, you don't need an example upon which to apply it. Most games require a mini-max algorithm.
So if you want one, decide how it must behave. Then write a test for at least one example of that behavior.
Post your test. (Not a game, but just a test of the data that would result from a game.)
If your algorithm does not work, your game program can't work.
Hint: A mini-max algorithm depends only upon the evaluations of game paths, not upon the game being played.
I'm trying to create a library of some common algorithms so that people will be able to use them easily. I created an object called Compare, which has some methods that would be useful in these algorithms.
Code for Compare:
class Compare(list):
def __init__(self,arr):
self.arr = arr
def __compare(self,u,v):
# Compares one item of a Compare
# object to another
if u < v:
return 1
if u == v:
return 0
if u > v:
return -1
def __swap(self,arr,i,j):
# Exchanges i and j
temp = arr[i]
arr[i] = arr[j]
a[j] = temp
def __determine(self,arr):
# Determines if the array is sorted or not
for i in range(0,len(array)):
if self.__compare(arr[i], arr[i+1]) == -1:
return False
return True
def __printout(self,arr):
for i in range(0,len(array)):
return arr[i] + '\n'
def sorted(self):
if self.__determine(arr):
return True
return False
Here's one of the algorithms that uses this class:
def SelectionSort(array):
try:
array = Compare(array)
for ix in range(0, len(array)):
m = ix
j = ix+1
for j in range(0,len(array)):
if array.__compare(array[j], array[m]) == -1:
m = j
array.__swap(arr, ix, m)
return array
except(TypeError) as error:
print "Must insert array for sort to work."
The problem I'm having is that whenever I try to use this or any of the other algorithms, it returns an empty array instead of the sorted array. I'm not sure how to get the Compare object to return the sorted array.
I'm pretty sure this is what is happening. When you call :
array = Compare(array)
You overwrite the reference to the original array. Array is now a reference to a Compare object. Replace array with array.arr (or name array something better) and this should work I think! :)
Remember that python is loosely typed, so that your "array" variable is just a reference to some data. In this case, you are switching it from a reference to a list to a reference to a Compare object.
Think about:
>>> x = 1
>>> x
1
>>> x = 's'
>>> x
's'
And think about what happens to the 1 ;)
Your code has many problems some of them make it to fail
for example
in sorted you are using a maybe global arr that doesn't exist, instead
of self.arr).
in swap you also use a[j] = temp, but a is local to the method and you do not use it for anything
you are using two underscores for your methods. This puts name mangling to work, So the calls in the function do not work in the way you do them. Probably you want a single underscore to indicate that this are private methods.
But the main problem is that Compare is not returnig a list. For that you need:
class Compare(list):
def __init__(self, arr):
list.__init__(self, arr)
then:
>>> print Compare([1,2,3,4])
[1, 2, 3, 4]
In this way you should use in your methods self instead of self.arr because your instance is a list (or an instance of a subclass of list).
So the following is your code modified to actually work. The only problem is that your sorting algorithn is wrong an it is not sorting right. But you can do from here I suppose:
class Compare(list):
def __init__(self, arr):
list.__init__(self, arr)
def _compare(self, u, v):
# Compares one item of a Compare
# object to another
if u < v:
return 1
if u == v:
return 0
if u > v:
return -1
def _swap(self, i, j):
# Exchanges i and j
temp = self[i]
self[i] = self[j]
self[j] = temp
def _determine(self):
# Determines if the array is sorted or not
for i in range(len(array)):
if self._compare(self[i], self[i+1]) == -1:
return False
return True
def _printout(self):
for i in self:
return i + '\n'
def sorted(self):
if self._determine():
return True
return False
def SelectionSort(array):
try:
array = Compare(array)
for ix in range(len(array)):
m = ix
j = ix + 1
for j in range(len(array)):
if array._compare(array[j], array[m]) == -1:
m = j
array._swap(ix, m)
return array
except(TypeError) as error:
print "Must insert array for sort to work."
You're not returning the array, you're returning a Compare wrapped around the array. If you intend Compare to be a proxy, the wrapping is incomplete, as you don't forward the standard container operations to the proxied array. In addition, you'll need to consistently use the Compare instance. Currently, you sometimes use the Compare and other times use the original sequence object, such as every place you pass the sequence to a method. Instead, use the Compare object within its own methods.
However, that's having Compare do two things: be an algorithm collection, and be a sequence. If you keep the Compare object separate and work on the list directly, you can switch out the algorithms easily. This is the more typical approach; list.sort works this way, taking a comparator as an argument. You'll also need to fix your implementation of Compare, which uses the wrong variable name in numerous places (array, when the local variable is named arr). If you want anyone to use your library, it's going to have to be much better designed.
As further reasons not to make Compare a sequence, consider what happens when you need to change comparison methods: you end up wrapping the Compare in another, making the wrapped Compare useless.
Consider the approach used in math: an order is a relationship defined on a set, not an intrinsic part of the set, and it especially isn't a part of sequences of items from the set. This reveals another conceptual error with your original approach: it couples an ordering (which is a set relationship) with operations on sequences of elements from the set. The two should be kept separate, so that you can use different comparisons with the sequence operations.
Off-Topic
There are a number of other mistakes of various types in the code. For example, in SelectionSort you assume that type errors must be due to a non-sequence being passed as array. Comparing instances of uncomparable types (such as 0 and 'd') will also result in a type error. For another example, Compare.sorted is useless; it's of the pattern:
if test:
return True
return False
This is logically equivalent to:
return test
which means Compare.sorted is equivalent to Compare.__determine. Make the latter the former, as sorted is a more descriptive name. "determine" is too ambiguous; it begs the question of what's being determined.
You can get more code reviews at codereview.stackexchange.com.