Is it possible to solve tower of hanoi halfway? I've done extensive research to look for codes that solves the user's configuration halfway but I've yet to find one. This is for an assignment and I require the code to take over from where the user has stopped solving and continue solving it for the user, without resetting the puzzle to square one.
I understand that there are recursion algorithms out there readily available but that is not what I'm searching for.
I'm searching for algorithms that can take over from where the user has solved until, and then continue solving from there.
Any ideas?
So far, I've come up with an algorithm that stores the optimized algorithms( which is being done by recursion) into an array, and then checks if the user's input is equal to any found in the array, and then continue solving from there. However, the problem lies when the user's configuration is not found in the optimized algorithm array.
The following are my codes so far ( I've excluded the stack.py codes):
def solveHalfway(n, start, end, middle, count):
gameInstance.stackA = [3,2]
gameInstance.stackB = []
gameInstance.stackC = [1]
loopCounter = 0 # initialise loopCounter as 0
moveCounter = 0 # initialise the move index the user is stuck at
indicator = 0 # to indicate whether the user's config equals the solution's config
while loopCounter < arrayOfStacks.size(): # while loopCounter size has not reached the end of arrayOfStacks
if loopCounter != 0 and loopCounter % 3 == 0: # if 3 stacks have been dequeued
moveCounter += 1
if gameInstance.getUserConfig() == tempStack.data: #check whether user's config is equal to the solution's config
indicator += 1
print "User is stuck at move: ", moveCounter #this will be the current move the user is at
while arrayOfStacks.size() != 0: # while not the end of arrayOfStacks
correctMovesStack.push(arrayOfStacks.dequeue()) # add the moves to correctMovesStack
if correctMovesStack.size() == 3: # if 3 stacks have been dequeued
print "Step:", moveCounter , correctMovesStack.data # display the step number plus the correct move to take
moveCounter+=1 # increase move by 1
while correctMovesStack.size() != 0: # if correct moves stack isn't empty
correctMovesStack.pop() # empty the stack
return
else:
while tempStack.size() != 0: # check if tempStack is empty
tempStack.pop() # empty tempStack so that it can be used for the next loop
tempStack.push(arrayOfStacks.dequeue()) #dequeue from arrayOfStacks for a total of 3 times and push it to tempStack
else:
tempStack.push(arrayOfStacks.dequeue()) #dequeue from arrayOfStacks for a total of 3 times and push it to tempStack
loopCounter +=1 # increase loop counter by 1
if indicator == 0:
moveWith3Towers(noOfDisks, stackA, stackC, stackB, count)
print indicator
To solve the Towers of Hanoi from an arbitrary position, you can use a recursive procedure similar to the standard solution that works from the standard start position.
It just has to be a little more general.
Write a recursive procedure moveDisks(maxSize,targetPeg) that moves all the disks with size <= maxSize to the peg targetPeg, like this:
Find the largest disk m such that m.size <= maxSize and m is not on targetPeg. If there is no such disk, then return, because all the disks with size <= maxSize are already in the right place.
Let sourcePeg be the peg where m is currently, and let otherPeg be the the peg that isn't sourcePeg or targetPeg.
Call moveDisks(m.size-1, otherPeg) recursively to get the smaller disks out of the way.
Move m from sourcePeg to targetPeg.
Call moveDisks(m.size-1, targetPeg) recursively to put the smaller disks where they belong.
In python, I would write it like this. Note that I used a different representation for the game state that works better for this algorithm and doesn't allow any illegal positions:
#
# Solve Towers of Hanoi from arbitrary position
#
# diskPostions -- the current peg for each disk (0, 1, or 2) in decreasing
# order of size. This will be modified
# largestToMove -- move this one and all smaller disks
# targetPeg -- target peg for disks to move
#
def moveDisks(diskPositions, largestToMove, targetPeg):
for badDisk in range(largestToMove, len(diskPositions)):
currentPeg = diskPositions[badDisk]
if currentPeg != targetPeg:
#found the largest disk on the wrong peg
#sum of the peg numbers is 3, so to find the other one...
otherPeg = 3 - targetPeg - currentPeg
#before we can move badDisk, we have get the smaller ones out of the way
moveDisks(diskPositions, badDisk+1, otherPeg)
print "Move ", badDisk, " from ", currentPeg, " to ", targetPeg
diskPositions[badDisk]=targetPeg
#now we can put the smaller ones in the right place
moveDisks(diskPositions, badDisk+1, targetPeg)
break;
Test:
> moveDisks([2,1,0,2], 0, 2)
Move 3 from 2 to 0
Move 1 from 1 to 2
Move 3 from 0 to 1
Move 2 from 0 to 2
Move 3 from 1 to 2
Related
I am working on a coding problem and my solution passes around 1/4 of the test cases and I can't figure out why.
The code challenge is:
There are n people in a company, numbered from 1 to n, and every person (except for one) has a boss.
At a dinner, a subset m from the n people from the company come. You want to figure out how many people could pay for the dinner. A person can only pay for the dinner if their boss (or indirectly any boss above them, so for example their bosses boss) is not present at the dinner.
Input
First line: n and m separated by space
Second line: n integers, integer i denoting that the ith person's boss is person i. If i is 0, the person doesn't have a boss (he is the main boss)
Third line: m integers, denoting the people that come to the dinner
Output
The number of people who could pay for the dinner
Example
6 5
5 4 4 5 0 1
5 1 3 2 4
Answer
1
The main boss is present, he is the only one that can pay.
I was thinking of making the boss relations into a graph and then counting the number of distinct components. Is this a correct approach? Do I maybe have 0-index errors?
My code:
class Graph:
def __init__(self, V, ppl):
self.V = V
self.ppl = ppl
self.M = len(ppl)
self.adj = [[] for i in range(self.V)]
self.visited = [False for i in range(self.V)]
def NumberOfconnectedComponents(self):
visited = [False for i in range(self.V)]
count = 0
for v in range(self.M):
if (self.visited[self.ppl[v]] == False):
self.DFSUtil(v)
count += 1
return count
def DFSUtil(self, v):
self.visited[v] = True
for i in self.adj[v]:
if (not self.visited[i]):
self.DFSUtil(i)
def addEdge(self, v, w):
self.adj[v].append(w)
# Driver code
if __name__=='__main__':
n, m = map(int, input().split())
bosses = [int(i) for i in input().split()]
people = [int(i) - 1 for i in input().split()]
g = Graph(n, people)
for person in range(n):
fro = person
to = bosses[person]
if to == 0:
continue
else:
g.addEdge(fro, to - 1)
print(g.NumberOfconnectedComponents())
Example when my code goes wrong:
INPUT:
5 3
5 5 4 1 0
1 2 3
CORRECT OUTPUT: 2
MY OUTPUT: 3
There are a few issues in your attempt:
The information in self.ppl is not used where it should. In NumberOfconnectedComponents the variable v is an index in self.ppl, but apart from the if condition, you wrongly treat that v as a person (when you pass it to DFSUtil). You should pass self.ppl[v].
DFSUtil does not use self.ppl at all, so it assumes all people are present.
count is counting the number of paths you can find from unvisited (present) people, which is not the number of disconnected components.
Not a problem, but it is also a bit strange that you store the people as 0-based indexes (by correcting with -1), but don't the same when storing the bosses. For those you make the correction (of -1) later, at the time of adding the edge.
Also not a problem, but the name self.adj suggests that you are storing the children of the node in that list, but in fact, it stores the parent of the node, and so self.adj[v] shouldn't even have to be a list -- a node has only one parent (or none). You could of course decide to use adj to store the children, but then your addEdge should swap u and v.
Algorithm
You can indeed use recursion to walk up the tree (as you do), but then you should count the number of present persons for which you cannot find (upwards) a boss that is present. And something like visited can be used to avoid double work: a dictionary (or list) that gives the answer for already visited nodes:
Code
def solve(boss_of, present_people):
boss_is_present = [None] * len(boss_of)
present = set(present_people)
def find_boss(person):
if boss_is_present[person] is None: # undetermined
if boss_of[person] in present: # direct boss is present
boss_is_present[person] = True
elif boss_of[person] == -1: # it is the root
boss_is_present[person] = False
else:
boss_is_present[person] = find_boss(boss_of[person])
return boss_is_present[person]
count = 0
for person in present_people: # edge
if not find_boss(person):
# no higher in hierarchy is present
count += 1
return count
# Driver code
if __name__=='__main__':
n, m = map(int, input().split())
boss_of = [int(i) - 1 for i in input().split()]
present_people = [int(i) - 1 for i in input().split()]
print(solve(boss_of, present_people))
A bit more obscure, but at the end of solve you can remove the definition of count by just returning this expression:
return len(present_people) - sum(int(find_boss(person))
for person in present_people)
Iterative solution
The above solution could bump into a stack overflow error if the input size is large, and the tree has a great height -- this may happen when the tree is degenerate, where every boss has about 1 subordinate.
Here is an iterative solution that maintains an explicit stack:
def find_boss(person):
stack = []
found = False
while person >= 0 and boss_is_present[person] is None:
stack.append(person)
person = boss_of[person]
if person in present: # boss is present
found = True
break
for person in stack:
boss_is_present[person] = found
return found
return len(present_people) - sum(int(find_boss(person))
for person in present_people)
Observation
There is an implicit assumption that the boss relation has no cycles: we can't have A and B being each other's boss. Moreover, because each person but one has a boss, the graph is connected. In other words, the graph is a single tree.
Connected components
A person can only pay for the dinner if their boss (or indirectly any boss above them, so for eg. their bosses boss) is not present at the dinner.
This implies that your connected components approach is not going to give the right answer. Consider this org chart:
A (CEO)*
|
B (middle manager)
|
C (line worker)*
People marked with * are present at the dinner. Then clearly, A is the only one who could pay, but there are two connected components {A} and {C}.
Hint towards solution
One way is to traverse the tree from the top down in a depth-first or breadth-first search (order doesn't matter). As soon as you encounter a person X who is present, you count that person and abort that branch of the search: X can pay (because nobody above them was present), and nobody below X can pay (because X is, directly or indirectly, their boss).
This solution requires that you build the parent-to-children relation in memory out of the child-to-parent relation from the input, but it runs in the theoretically optimal O(n) time. (An O(m) algorithm would be nice, but reading the input is already O(n) so it doesn't bring us anything.)
The following code checks for all straights in a five-card hand (except 5-high, which I add in as an elif)
def straight(values,vset):
if (max(vset) - min(vset) == 4) and numpair(values) == False and detset(values) == False and quads(values) == False:
#STRAIGHT DETECTED
Vset is just a set containing the values. The problem is, I cannot figure out a way to adapt this code to evaluate a 7-card holdem hand. Any advice?
While #JohnGordon's solution works it wastefully iterates 5 times for each rank value.
A more efficient approach would be to iterate the rank from 2 to 14 and simply use a counter to keep track of the number of times so far the rank exists in the cards consecutively, and if a consecutive rank doesn't exist, reset the counter. Determine that there is a straight if the counter reaches 5. To account for the fact that an Ace (assuming its rank is 14 here) can be regarded as a 1 to form a straight with 2, 3, 4, and 5 as well, you can prepend 14 to the range of 2 to 14 for iteration:
count = 0
for rank in (14, *range(2, 15)):
if rank in vset:
count += 1
if count == 5:
print('Straight found')
break
else:
count = 0
else:
print('Straight not found')
I don't know how the code works now, because you haven't shown us the code for numpair(), detset() and quads().
However, working from a clean slate, this is how I would do it:
# assume rank values are numeric 2-10, J=11, Q=12, K=13, A=14
# iterate over each rank 2 thru 10
for rank in range(2, 11):
# if rank+0, rank+1, rank+2, rank+3, and rank+4 are all present, we have a straight
if all(rank+n in vset for n in range(0,5)):
print 'we have a straight'
break
# if we never broke out of the loop, we never found a straight
else:
print 'we do not have a straight'
I'm working through an 'easy' HackerRank exercise, and I'm trying to apply multiple conditions to items in a list. The 'solution' I attempted appears consistent with others discussed on the site, but does not work. I am interested in learning why it fails, because I cannot discern my error.
The purpose of the function is to count the valleys along a person's walk. The relative elevations of the walk are stored in a string (ie. 'DDUU' for down, down, up, up). The walk begins and finishes at sea level. The function accepts the number of steps 'n' and the route string. In the case above, it should return v = 1, and in fact, it does. However, when I run this on longer cases, the function's returns are incorrect.
def countingValleys(n, s):
valleys = 0
position = 0
positions = []
for step in s:
if step == 'U':
position += 1
else:
position -= 1
positions.append(position)
for position in positions:
if positions[position] < 0 and positions[position+1] == 0:
valleys += 1
return valleys
s = 'DDUUUUDDDDUUDDUU'
v = countingValleys(16, s)
In this case, len(s) = 16 and the number of valleys is 3, but the number returned is 4. I'm trying to understand the error. Examples of new code are appreciated, but I mostly want to know what is wrong within the code above and how that might be adjusted. I am hoping to better understand multiple conditions, not just fix the code.
Thanks in advance!
instead of :
for position in positions:
if positions[position] < 0 and positions[position+1] == 0:
valleys += 1
you need:
for i in range(n):
if positions[i] < 0 and positions[i+1] == 0:
valleys += 1
The following lines of code are erroneous:
for position in positions:
if positions[position] < 0 and positions[position+1] == 0:
And I suppose you wanted to have something like:
for i in range(len(positions)-1):
if positions[position] < 0 and positions[position+1] == 0:
For example: If you have the following
s = 'DDDUUU', then your positions array looks like this: [-1, -2, -3, -2, -1, 0] and you will check position[-2] two times: (position[-2] is the 2nd value of positions read from the right and is -1.)
Both times your if will evaluated to true and thus you get two values and this is surely not intended.
My code is showing bellow
import math,sys
#create a list with numbers
def create_list():
num_list=[]
for num in range(int(input("insert start point: ")),int(input("Insert end point: "))):
num_list.append(num)
return num_list
#function to find triangular numbers
def get_triangles(numlist):
triangles = []
for i in numlist:
if (check_triangle(i)):
triangles.append(i)
return triangles
#function to check number is triangular or not
def check_triangle(n):
return math.sqrt((8*n)+1).is_integer()
#function main to run the process
def main():
numlist = create_list()
print(get_triangles(numlist))
Even though it seems like the task is completed it was not. I tried it with the range of 0 - 100000000(1*10^8) numbers . it is cause to stuck my laptop any method that can complete this task ?
DO NOT PRINT A LIST THAT LARGE. Instead write it to a file, that way you can open the file afterward. The program can't efficiently write that much information into the console. I find that printing stuff to the console makes a programs a ton less efficient.
Additionally, I read some of the comments on your code and they state it isn't efficient and I would have to concur.
Here is piece of code I wrote up. It takes a bit of interpretation, but I was in a hurry. Just reply if you need help understanding it.
def getTriangles(input1,input2): #input1 is the min value and input2 is the max value
li = [] #the list where all of the numbers will go
i = 0 #an integer that acts how much another layer of the triangle would have
j = 0 #the most current number that it is on
while True: #I whipped up this algorithm in a couple minutes, so there is probably a more efficient way than just looping through all of them, but it is faster than the current one being used
i += 1 #i has to increment to act as the increase of a side
if j > input2: #if the value that could be added is greater than the max number, than just end the function and return the list
return li
if j >= input1: #if the number qualifies the minimum number requirements, then the program will add it to the list, otherwise it will ignore it and continue on with the function
li.append(j)
j += i #this simulates adding in another layer of the triangle to the bottom
This would be a way to use it:
print(getTriangles(1,45))
I trust you can look up how to write content to a file.
It appears that you are just trying to generate all triangle numbers within a range. If this is so, computing them directly is substantially quicker than checking via square root.
Note that you can generate triangular numbers by simply adding consecutive numbers.
T_0 = 0
T_1 = T_0 + 1 = 1
T_2 = T_1 + 2 = 3
T_3 = T_2 + 3 = 6
...
If you want to keep it simple, you can create a function to keep generating these numbers from n = 0, keeping them when they enter the desired range, and continue until it exceeds the upper bound.
def generate_triangular_numbers(a, b):
"""Generates the triangular numbers in [a, b] (inclusive)"""
n, t = 0, 0
triangles = []
while t < a:
n += 1
t += n
while t <= b:
triangles.append(t)
n += 1
t += n
return triangles
So I'm trying to get a little more proficient with Python, and decided that making a maze would be a fun thing to know how to do. I found this page that goes over a bit of how to do it.
create a CellStack (LIFO) to hold a list of cell locations
set TotalCells = number of cells in grid
choose a cell at random and call it CurrentCell
set VisitedCells = 1
while VisitedCells < TotalCells
find all neighbors of CurrentCell with all walls intact
if one or more found
choose one at random
knock down the wall between it and CurrentCell
push CurrentCell location on the CellStack
make the new cell CurrentCell
add 1 to VisitedCells
else
pop the most recent cell entry off the CellStack
make it CurrentCell
endIf
endWhile
Now, I've got the following code, although it isn't much past the obvious stuff in the pseudocode.
class Cell:
top_wall = 0
bottom_wall = 0
left_wall = 0
right_wall = 0
def knock_down(self,wall):
if wall is 'top_wall' and self.top_wall is 0:
self.top_wall = 1
if wall is 'bottom_wall' and self.bottom_wall is 0:
self.bottom_wall = 1
if wall is 'left_wall' and self.left_wall is 0:
self.left_wall = 1
if wall is 'right_wall' and self.right_wall is 0:
self.right_wall = 1
else
return 'Error: Wall Already Gone'
maze = [10][10]
CellStack = [] # LIFO stack to hold list of cell locations
TotalCells = 100 # Number of cells in grid
VisitedCells = 0 # Cells that have been visited
CurrentCell = 0 # The current cell
while VisitedCells < TotalCells:
I'm not sure that the class is the best way to do the cells, but I haven't thought of another way to do it yet. However, I've run into a bit of a problem for checking for the neighbors of a cell. The find all neighbors of CurrentCell with all walls intact is throwing me for a bit of a loop.
How can you check whether cells are neighbors?
You can give each cell a position, stored as two integers. Then, two cells are neighbors if those integers are neighbors.
def isCellNeighbor(c1, c2):
if abs(c1.x - c2.x) == 1: return True
if abs(c1.y - c2.y) == 1: return True
return False
The above considers two cells as being neighbors if at least a corner of each one touches the other. You can tweak it to suit your needs.
PS: have a look at the amazing collection of maze algorithms