I am trying to solve this problem.
There is a robot starting at position (0, 0), the origin, on a 2D plane. Given a sequence of its moves, judge if this robot ends up at (0, 0) after it completes its moves.
The move sequence is represented by a string, and the character moves[i] represents its ith move. Valid moves are R (right), L (left), U (up), and D (down). If the robot returns to the origin after it finishes all of its moves, return true. Otherwise, return false.
Note: The way that the robot is "facing" is irrelevant. "R" will always make the robot move to the right once, "L" will always make it move left, etc. Also, assume that the magnitude of the robot's movement is the same for each move.
Example 1:
Input: moves = "UD"
Output: true
Explanation: The robot moves up once, and then down once. All moves have the same magnitude, so it ended up at the origin where it started. Therefore, we return true.
Example 2:
Input: moves = "LL"
Output: false
Explanation: The robot moves left twice. It ends up two "moves" to the left of the origin. We return false because it is not at the origin at the end of its moves.
Example 3:
Input: moves = "RRDD"
Output: false
Example 4:
Input: moves = "LDRRLRUULR"
Output: false
Even though I solved it using counters as well as conditionals, I would like to see how I could use Python's OOP components to solve this. How can I separate out the valid moves, which are R (right), L (left), U (up), and D (down) into separate methods for better abstraction, so that I could add more methods in future? How would the refactored code look like? This is the solution:
class Solution(object):
def judgeCircle(self, moves):
x = y = 0
for move in moves:
if move == 'U': y -= 1
elif move == 'D': y += 1
elif move == 'L': x -= 1
elif move == 'R': x += 1
return x == y == 0
Here's one way to do it by encapsulating the data and the code that acts on it — both key OOP features. Note though that using "getters" and "setters" is not "pythonic" (because they are generally unnecessary and can be added retroactively if the need ever arises for some reason).
class Solution:
class Mover:
def __init__(self, x, y):
self.x, self.y = x, y
def new_pos(self, x, y):
return x + self.x, y + self.y
WALKS = dict(U=Mover(0, -1), D=Mover(0, 1),
L=Mover(-1, 0), R=Mover(1, 0))
def judge_circle(self, moves):
x = y = 0
for id in moves:
x, y = self.WALKS[id].new_pos(x, y)
return x == y == 0
solution = Solution()
sequences = "UD", "LL", "RRDD", "LDRRLRUULR"
for moves in sequences:
print(solution.judge_circle(moves))
Related
Question:
There is a robot starting at position (0, 0), the origin, on a 2D plane. Given a sequence of its moves, judge if this robot ends up at (0, 0) after it completes its moves.
The move sequence is represented by a string, and the character moves[i] represents its ith move. Valid moves are R (right), L (left), U (up), and D (down). If the robot returns to the origin after it finishes all of its moves, return true. Otherwise, return false.
Note: The way that the robot is "facing" is irrelevant. "R" will always make the robot move to the right once, "L" will always make it move left, etc. Also, assume that the magnitude of the robot's movement is the same for each move.
Input: moves = "UD"
Output: true
Explanation: The robot moves up once, and then down once.
All moves have the same magnitude, so it ended up at the origin where it started.
Therefore, we return true.
I have the following solution, which seems to be wrong for sequences = "UD", which should return True. Could someone help me understand what I am doing wrong here and how I could fix it?
class Solution:
class Mover:
def __init__(self, x, y):
self.x, self.y = x, y
def new_pos(self, x, y):
return x + self.x, y + self.y
WALKS = dict(U=Mover(0, -1), D=Mover(0, 1),
L=Mover(-1, 0), R=Mover(1, 0))
def judge_circle(self, moves):
x = y = 0
for id in moves:
x, y = self.WALKS[id].new_pos(x, y)
return x == y == 0
def move_sequences(self,sequences):
for moves in sequences:
return (solution.judge_circle(moves))
if __name__ == "__main__":
solution = Solution()
sequences = "UD"
print(solution.move_sequences(sequences))
This solution seems overthinking it by quite a bit. You can just make a counter of each of the 4 directions and figure out if you have the same number of Us relative to Ds and Ls relative to Rs. return s.count("U") == s.count("D") and s.count("L") == s.count("R") gives you a linear solution that can be optimized into a single pass with something like
from collections import Counter
d = Counter(moves)
return d["D"] == d["U"] and d["R"] == d["L"]
As for your code,
for moves in sequences:
return (solution.judge_circle(moves))
looks funny to me. Returning on the first iteration means the loop is pointless. moves here is misleadingly named -- it's only a single character "U". judge_circle already does a loop, so if you really want to brute-force it, you'll only want one loop over the sequence rather than two.
Your task is simple:
def judge_circle(moves):
if moves.lower().count('U') == moves.lower().count('D') and moves.lower().count('L') == moves.lower().count('R'):
return True
else:
return False
print(judge_circle('UD'))
You only have to check whether the number of 'ups' equals the numbers of 'downs', and 'lefts' equal 'rights'.
Ok, a part from refactor advices, you can fix your script in a easy way.
def move_sequences(self,sequences):
for moves in sequences:
return (solution.judge_circle(moves))
fails because you pass a string in sequences and the for loop cycles over the letters, passing every single letter to judge_circle.
Remove the for loop and pass sequences to judge_circle!
So basically I decided to make a sudoku solver in python and recursive functions is most efficient, but I've been trying to understand this code from a youtuber and don't understand why each space (bo[row][col]) doesn't immediately reset to 0. The resetting of one space to 0 only occurs if solve(bo) is True, but if I look through the code, the board will only return True if the board is completely solved, so why doesn't this function just lead nowhere since solve(bo) will never be True?
def solve(bo):
find = find_empty(bo)
if not find:
return True # This is the only time that solve(bo) == True
else:
row, col = find
for i in range(1, 10):
if valid(bo, i, (row, col)):
bo[row][col] = i
if solve(bo):
return True
bo[row][col] = 0 # Yet here it resets the space to 0 if solve(bo) is False
return False
def valid(bo, num, pos):
for i in range(9):
if bo[pos[0]][i] == num and pos[1] != i:
return False
for i in range(9):
if bo[i][pos[1]] == num and pos[0] != i:
return False
box_x = (pos[1] // 3) * 3
box_y = (pos[0] // 3) * 3
for i in range(box_y, box_y + 3):
for j in range(box_x, box_x + 3):
if bo[i][j] == num and (i, j) != pos:
return False
return True
def find_empty(bo):
for y in range(9):
for x in range(9):
if bo[y][x] == 0:
return (y, x)
return False
There is some discrepancy between your explanation and comments in the code, but I'll do my best to explain the code anyway.
First solve() will try to find the first empty spot (i.e. one that is 0). If it can't find any, then the board is solved so it returns true.
If it does find a spot, then it will try to place numbers 1-9 there and check if it works with the previously entered numbers. Say 7 works (we don't know if 8 or 9 work as well because we haven't checked that yet). So we set the empty space to 7 and then pass this updated board in a recursive call. Essentially, this is like saying "if I force this spot to have the number 7, can you find a solution?"
If the recursive call returns true, it means there is a solution with 7 in that spot and hence the board has a solution, so we return true. If the recursive call to solve() returns false, then we know that there is no solution to the board with 7 in this spot, so we reset this spot to 0 and then try 8 (and then 9 if needed).
The thing to remember is that there is only one board (bo) in all the recursive calls - in other words, all the function calls are operating on the same variable bo. It doesn't create a copy of the board every time you make a recursive call. Lookup 'Pass by reference' and shallow vs. deep copies if you want to learn more about why.
I need to create a recursive function that iterates through all possible moves of a "4-in-a-row" game at a given depth and finds the best move.
The functions available are:
eval_pos(board, pid) # Returns eval score of a given board and pid(player id, either -1 or 1)
get_legal_moves(board) # Returns all legal moves in a tuple
The goal is to create a recursive function which finds what move gives the best score, given the best play from both parts.
def get_score(board, depth, pid):
moves = get_legal_moves(board)
evals = []
for move in moves:
board[move] = pid
evals.append(eval_pos(board, pid))
board[move] = 0 #0 signifies an empty board space, doing this to prevent filling the board
if depth == 0:
return max(evals)
idx = evals.index(max(evals))
board[moves[idx]] = pid
# Notice we are passing -pid on each new iteration
return get_score(board, depth-1, -pid, start_pid)
What I've come up with so far, does not work at all. It essentially does what I want in reverse and skipping a lot of positions, where it checks the best move for player1 in the first position, then the best move for player2 in the following position and so on. However, it needs to search through ALL the moves and then determine what is best given the best counterplay. Is there an efficient way to accomplish this?
This solution seems to work, however it is extremely slow and can only reach a depth of 5 before it becomes unusable.
def minimax(board, depth, max_turn):
# Base case
if depth == 0:
return eval_pos(board)
eval = eval_pos(board)
if eval is None:
return 0
if abs(eval) == 100:
return eval
moves = get_legal_moves(board)
if max_turn:
return max([minimax(update_board(board, move, 1), depth-1, False) for move in moves])
else:
return min([minimax(update_board(board, move, -1), depth-1, True) for move in moves])
I have an assignment for a programming unit that asks this:
create the function enclosing(board, player, pos, direct), that represents the rules of Reversi according to the following specifications.
A board position is represented by a pair (r, c) where r and c are each integers from the range
range(8) representing a row index and a column index, respectively. For instance, the position \b3" is
represented by (2, 1). The row and column order of the \b3" style and the specication of position
is reversed. This is because it is natural to constuct lists of lists in such a way that the outer lists
correspond to rows, and the inner list positions corerspond to column positions, so we reference them
with row rst, then column. This row, column convention is quite common across maths and computer
science.
A direction is represented by a pair (dr, dc) where dr and dc are each integers from the set f-1, 0,
1g. For instance, \horizontal to the left" is described by (0, -1), \diagonal to the right and down" is
described by (1, 1), and so on).
The function enclosing(board, player, pos, dir) represents whether putting a player's stone on
a given position would enclose a straight line of opponent's stones in a given direction:
Input: A board conguration board, an integer player from the set f1, 2g, a board position pos and a direction dir.
Output: True if board contains a stone of player in direction dir from position pos and all positions
on the straight line between that stone and pos contain stones of the other player, and there is at
least one stone belonging to the other player on the straight line; False otherwise.
This is what I have:
def enclosing(board, player, pos, direct):
if player == 1:
a = direct[0]
b = direct[1]
i = 1
while i < 8:
newpos = (pos[0] + i*a , pos[1] + i*b)
if board[newpos[0]][newpos[1]] == 1:
return True
elif board[newpos[0]][newpos[1]] == 2:
i = i + 1
else:
return False
Also keep in mind this is a beginners course and I have about a months experience on python.
The code in your edit looks good, and is what I was getting at. Good luck with the rest of the project!
A couple edge cases:
board[newpos[0]][newpos[1]] will go out of bounds
Your function will return True in the case XOOOOX, which is not a capture by Othello rules (not sure if your assignment defines it differently
I strongly recommend writing a couple simple tests just to make sure your code works. They don't need to cover the full range of cases, and doesn't need to be the full board. It's usually not required, but makes it easier to evaluate: just hit "run" instead of trying to reason through your code.
Here's an example:
def test():
assert enclosing([[0, 0, 0], [0,0,0],[0,1,2]], 1, (0,2), (1,1)) == True
So I'm trying to write a little simulator thing with pygame, but im stuck
I'm trying to make particles that fall and settle but i want them to stack and stop when they hit a wall
This may sound confusing so here is an example:
http://www.coolmath-games.com/0-sugar-sugar/
I want to make particles that resemble the sugar in the game above:
I started by trying:
if pygame.sprite.spritecollideany(self, self.game.block_list):
self.rect.x += 0
self.rect.y += 0
but then the particles just stop and they don't roll down sloped surfaces
also I need to know how to check if a sprite collides with any other sprite in its group
So if anyone knows how I can duplicate this liquid like particle movement in pygame that would be awesome!
Thank You!
As I stated above, I tried to write the exactly same game with pygame too but left it uncompleted.
First of all, I preferred NOT to store these particles as different objects. Instead I used a dictionary to store their coordinates. I made it so because there are HUNDREDS of them and you have to check for collisions ~50 times per second for each of them. If you try to make them all different objects, it may go out of hand at some point.
After you detect a collision, in order to make them roll down sloped surface, let them move diagonally too. First check for the cell below, if that cell is not empty, check for the cells at bottom left and bottom right of the particle.
Btw, I found my function that moves the particles but it is not really readable.
def spawnSugar(spawnPoint) :
global sugarList,mapDict
mapDict[spawnPoint] = 1
sugarList.append(spawnPoint)
def moveAll() :
global mapDict,sugarList
sugarListTmp = sugarList
sugarList = []
for sugarX,sugarY in sugarListTmp :
# m stands for the vertical movement (1 for down, 0 for staying still)
# k stands for horizontal movement (-1 for left, +1 for right)
m = 1
if mapDict[( sugarX , (sugarY+1)%mapSizeY )]==0:
# checks whether the coordinate below this particle is empty
k = randint( -(mapDict[((sugarX-1)%mapSizeX , (sugarY+1)%mapSizeY)]==0) , mapDict[((sugarX+1)%mapSizeX , (sugarY+1)%mapSizeY)]==0 )
# If it is empty; randomly chooses 1 of the 3 coordinates below the particle (1 of them is just below and the other 2 are diagonally below)
elif mapDict[((sugarX-1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX-1)%mapSizeX,(sugarY)%mapSizeY)]==0 and mapDict[((sugarX+1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX+1)%mapSizeX,(sugarY)%mapSizeY)]==0:
# If the coordinate below the particle is not empty but other 2 diagonals are empty
k = -1 if randint(0,1) else 1 #chooses 1 of them randomly
else : # If at most 1 of these 2 diagonal coordinates are empty
k = (mapDict[((sugarX+1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX+1)%mapSizeX,(sugarY)%mapSizeY)]==0) or -(mapDict[((sugarX-1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX-1)%mapSizeX,(sugarY)%mapSizeY)]==0)
if not k: # If none of them are empty
m = 0
mapDict[(sugarX,sugarY)] = 0
mapDict[((sugarX+k)%mapSizeX,(sugarY+m)%mapSizeY)] = 1
sugarList.append(((sugarX+k)%mapSizeX,(sugarY+m)%mapSizeY))
# Values to assign before entering the main loop
mapDict = {}
sugarList = []
for x in range(mapSizeX):
for y in range(mapSizeY):
mapDict[(x,y)] = 0