I'm trying to solve the coding challenge A child's play on Codingame using python.
With my program I can pass the first two test cases but when the test requires a lot of loops my program goes in timeout. What could I improve?
To fully understand the problem the details of the challenge are needed but I don't want to copy and paste them here because I'm not sure it's allowed.
I try to explain the problem with my words. Given this input:
12 6
987
...#........
...........#
............
............
..#O........
..........#.
O is the character starting point.
# are the walls you can not step on
. is where the character can step
In this example w=12 (width of the matrix) and h=6 (height of the matrix).
n = 987 is the number of steps the character has to take.
Required Output:
In this case 7 1 the position of the character after the number of moves given
Rules:
The character starts always by moving upwards
When a wall is encountered the character turns clockwise and keeps moving
The walls are placed so that the caracter can not get stuck and can not exit the matrix.
When I run the program with that test case I get the right result.
With the following test case instead:
14 10
123456789
..#...........
....#..#......
.#O.....#.....
..............
..............
.......##...#.
............#.
.#........###.
.#.#..........
..............
I get:
Failure
Process has timed out. This may mean that your solution is not optimized enough to handle some cases.
This is the code I managed to write:
import math
import sys
def find_initial_position(maze, w, h):
for i in range(0, h):
for j in range(0,w):
if maze[i][j] == "O":
return [i, j]
return -1
def can_move(maze, direction, x, y):
if direction == "U":
if maze[ x -1 ][ y ] == "#":
return False
elif direction == "R":
if maze[ x ][ y + 1 ] == "#":
return False
elif direction == "D":
if maze[ x +1 ][ y ] == "#":
return False
elif direction == "L":
if maze[ x ][ y-1 ] == "#":
return False
return True
def turn_clockwise(direction):
directions = ["U", "R", "D", "L"]
return directions[ (directions.index(direction) + 1) % 4 ]
def move(direction, coordinates):
if direction == "U":
coordinates[0] -=1
elif direction == "R":
coordinates[1] +=1
elif direction == "D":
coordinates[0] +=1
elif direction == "L":
coordinates[1] -=1
def main():
w, h = [int(i) for i in input().split()]
n = int(input())
maze = []
direction = "U"
position = [0, 0]
for i in range(h):
line = input()
maze.append(line)
position = find_initial_position(maze, w, h)
for i in range(0, n):
while not can_move(maze, direction, position[0], position[1]):
direction = turn_clockwise(direction)
move(direction, position)
print( "%(x)d %(y)d" %{"x": position[1], "y": position[0]} )
main()
I streamlined your code a little bit and made it somewhat more readable, by:
making use of matrix multiplication with numpy to do the 90° clockwise turns;
using the built-in str.index() to find the initial position.
Result below...
But really, this is missing the point.
If you look at the "mazes" in all the test cases, what's happening is that the "robot" is bouncing cyclically between four # obstacles in a rectangular pattern (could also be a more complex pattern). So with your approach, you're computing and re-computing the same short sequence of moves, millions and billions of times; even though the longest possible cycle cannot possibly have more moves than the number of squares in your small maze (order of magnitude).
What you should try to do is keep a continuous log of all the moves done so far (position, direction). And if – or rather, when – you end up in a (position, direction) where you've already been before, then you've covered one full cycle. No need to compute any more moves. Say your cyclic sequence is of length L and the total number of moves prescribed is n, then the final position will be sequence element number L mod n (or something like that, off-by-one errors notwithstanding).
import sys
import numpy as np
def is_obstacle(maze, position):
return maze[position[0]][position[1]] == '#'
def main():
w, h = [int(i) for i in input().split()]
n = int(input())
# Load maze
maze = []
for i in range(h):
line = input()
maze.append(line)
if 'O' in line:
# Found initial position
position = np.array([i, line.index('O')])
# Initial direction
direction = np.array([-1,0])
# Define actions
turn_clockwise = np.array([[0,-1],[1,0]])
# Walk maze
for i in range(n):
while is_obstacle(maze, position + direction):
direction = direction # turn_clockwise
position = position + direction
print( "%(x)d %(y)d" %{"x": position[1], "y": position[0]} )
main()
Related
k=int(input())
res=[2]
for i in range(2,k+1):
if i%2==0:
continue
else:
for j in range(2,i):
if i%j==0 or j%2==0 :
break
else:
res.append(i)
print(res)
This code is for finding prime numbers in a given range of numbers.
I tried to run the code but the list is having only number 2. Can anyone tell me what is happening?
If I remove j%2==0 it's working. I just want to know my mistake.
You should use your current result to accelerate your process. You only need to test divisibility by primes. But you are building a list of primes. So use it !
k=int(input())
primes=[]
for i in range(2,k+1):
if all(i%p!=0 for p in primes):
primes.append(i)
You can also improve by selecting only prime elements which are inferior to sqrt(i) like others suggested.
import math
k=int(input())
primes=[]
for i in range(2,k+1):
j=math.sqrt(i)
if all(i%p!=0 for p in primes if p<=j):
primes.append(i)
Your code had one issue, in the inner loop the or condition is incorrect, as highlighted by #kederrac. You don't need the j%2==0 as j always start from 2 and i%j==0 already covers the condition
k=int(input())
res=[2]
for i in range(2,k+1):
if i%2==0:
continue
else:
for j in range(2,i):
if i%j==0 :
break
else:
res.append(i)
print(res)
in your inner loopj variable starts from value 2 and then you have an if statement that is always True because j%2==0 is always 2%2==0 which is always True, so you always break from the first step of inner for loop iteration
you can use:
import math
k=int(input())
res=[]
for i in range(2, k+1):
for x in range(2, int(math.sqrt(i) + 1)):
if i % x == 0 :
break
else:
res.append(i)
# k = 20
output:
[2, 3, 5, 7, 11, 13, 17, 19]
for efficient prime generation, you can use the Sieve of Eratosthenes:
# Sieve of Eratosthenes
# Code by David Eppstein, UC Irvine, 28 Feb 2002
# http://code.activestate.com/recipes/117119/
def _gen_primes():
""" Generate an infinite sequence of prime numbers.
"""
# Maps composites to primes witnessing their compositeness.
# This is memory efficient, as the sieve is not "run forward"
# indefinitely, but only as long as required by the current
# number being tested.
#
D = {}
# The running integer that's checked for primeness
q = 2
while True:
if q not in D:
# q is a new prime.
# Yield it and mark its first multiple that isn't
# already marked in previous iterations
#
yield q
D[q * q] = [q]
else:
# q is composite. D[q] is the list of primes that
# divide it. Since we've reached q, we no longer
# need it in the map, but we'll mark the next
# multiples of its witnesses to prepare for larger
# numbers
#
for p in D[q]:
D.setdefault(p + q, []).append(p)
del D[q]
q += 1
k=int(input())
def gen_primes(k):
gp = _gen_primes()
p = next(gp)
while p < k:
yield p
p = next(gp)
res = list(gen_primes(k))
I have a string "x-xoxoo--" which represents a stage in a game Tic-Tac-Toe
x|-|x
o|x|o
o|-|-
I know how to check if one stage in a list is valid:
from math import *
def check(play):
x = 0
o = 0
for item in play:
if item == "x":
x = x+1
if item == "o":
o = o+1
return fabs(x-o) <= 1
I want to check if for example the list ["x-xoxoo--", "x-xoxoox-", "x-xoxooxo"] describes a possible sequence of consecutive moves in the game.
for example:
["----x----", "o---x----", "oo--x----"] is not valid
and another
["----xo---", "o---xo---", "x---xo---"] is not valid
I also know how to count differences between two sequences:
def difference(seq1, seq2):
count = 0
for i in range(len(seq1)):
if seq1[i] != seq2[i]:
count += 1
return count
Most problems like this are made easy or difficult by what data structure you use to represent the inputs. My solution is to represent a position as a set of tuples like {(0, 'x'), (4, 'o')}, where the first component of the tuple is the index of the board position, and the second is the symbol of the player.
My choice of this data structure is motivated by the simplicity of testing whether two board positions differ by one move, and testing whether the game has been won.
I'm going to assume that the sequence must be a whole game starting from an empty board, and that 'x' always plays first.
Converting a string to a set of these tuples is easy using a set comprehension with enumerate:
def string_to_position(board):
return { (i, s) for i, s in enumerate(board) if s in 'xo' }
The next step is to test whether a board position q can be made from position p by one extra move of player s. For this to be true,
p must be a subset of q,
The set q - p must have a single element,
That single element must be a move by player s.
The simplicity of testing this using sets is one motivation for my choice of data structure.
def one_more_move(p, q, s):
if p <= q:
diff = q - p
return len(diff) == 1 and list(diff)[0][1] == s
else:
return False
A sequence of legal moves in Tic-Tac-Toe cannot continue after one player has won, so we need to test whether a board position is a win.
That is, for each winning line for each player, we need to test whether that line exists on the board. To do this using sets, we can just test whether each "win" is a subset of the board position. The only hard part is listing all of the "wins"; there are 8 three-in-a-rows, but we need each for both players:
all_lines = [
# horizontal
(0, 1, 2), (3, 4, 5), (6, 7, 8),
# vertical
(0, 3, 6), (1, 4, 7), (2, 5, 8),
# diagonal
(0, 4, 8), (2, 4, 6),
]
all_wins = [
{ (i, s) for i in line }
for s in 'xo'
for line in all_lines
]
def is_win(p):
return any( win <= p for win in all_wins )
Now we're ready to write a function to test whether a sequence of positions is a valid game of Tic-Tac-Toe:
import itertools
def is_valid_game(positions):
# first, convert to our data structure
positions = [ string_to_position(p) for p in positions ]
# the game starts with an empty board
p = set()
won_already = False
# cycle between players x, o, x, o...
for q, s in zip(positions, itertools.cycle('xo')):
if won_already or not one_more_move(p, q, s):
return False
won_already = is_win(q)
p = q
# if we saw every position and didn't find any problem, then the
# sequence of positions must be a valid game of Tic-Tac-Toe
return True
Tests:
>>> is_valid_game(['----x----', 'o---x----', 'ox--x----'])
True
>>> is_valid_game(['----x----', 'o---x----', 'oo--x----'])
False # o is not allowed to play twice in a row
>>> is_valid_game(['----x----', '----o----'])
False # o is not allowed to play where x played
>>> is_valid_game(['o--------'])
False # o is not allowed to play first
>>> is_valid_game(['----x-x--'])
False # x can't start by making two moves
>>> is_valid_game(['----x----', 'o---x----', 'o--xx----', 'oo-xx----', 'oo-xxx---'])
True
>>> is_valid_game(['----x----', 'o---x----', 'o--xx----', 'oo-xx----', 'oo-xxx---', 'oooxxx---'])
False # can't keep playing after x wins
First off, your function for checking if a single position is valid can be simpler:
def check(position):
# there should either be the same number of "x"s as "o"s or one more "x"
return (position.count("x") - position.count("o")) in (0, 1)
To determine whether a sequence of moves is valid, we need to check that the first move is valid, then determine who's move it is
def to_move(position):
if (position.count("x") - position.count("o")) == 0:
return "x"
return "o"
then iterate over each position with the one that came before (we do this with zip(some_list, some_list[1:])), generating all the possible moves from the previous position (there can be at most 9)
def generate_all_moves(position):
moves = []
for index, piece in enumerate(position):
if piece == "-":
# strings are immutable so we need to convert it to a list
new_move = list(position)
new_move[index] = to_move(position)
# and convert it back to a sting
moves.append(''.join(new_move))
return moves
and checking if the current position is one of them.
def check_moves(positions):
if not check(position[0]):
return False
for prev_position, current_position in zip(positions, positions[1:]):
if current_position not in generate_all_moves(prev_position):
return False
return True
This works for any number of moves except 0 (which should return True), not just 3.
You can't make moves after a game has been won so you should also write a function that checks if a game is won, and if it's won in any move but the last one, return False.
It might be a bit cleaner to generate the entire game tree upfront (should take a trivial amount of ram, like a few MB) as a dictionary of position -> list of valid moves and then just looking up each position in it.
I am currently doing coursera course on algorithms. I have successfully completed this assignment. All test cases passed. My code looks messy and I want to know if there is any thing availiable in Python which can help run my code faster. Thanks
The problem statement is as follows: You are given a primitive calculator that can perform the following three operations with
the current number 𝑥: multiply 𝑥 by 2, multiply 𝑥 by 3, or add 1 to 𝑥. Your goal is given a
positive integer 𝑛, find the minimum number of operations needed to obtain the number 𝑛
starting from the number 1.
# Uses python3
import sys
def optimal_sequence(m):
a=[0,0]
for i in range(2,m+1):
if i%3==0 and i%2==0:
a.append(min(a[i//2],a[i//3],a[i-1])+1)
elif i%3==0:
a.append(min(a[i//3],a[i-1])+1)
elif i%2==0:
a.append(min(a[i//2],a[i-1])+1)
else:
a.append((a[i-1])+1)
return backtrack(a,m)
def backtrack(a,m):
result=[]
result.append(m)
current = m
for i in range(a[-1],0,-1):
if current%3==0 and a[current//3]==(i-1):
current=current//3
result.append(current)
elif current%2==0 and a[current//2]==(i-1):
current = current//2
result.append(current)
elif a[current-1]==(i-1):
current = current-1
result.append(current)
return result
n = int(input())
if n == 1:
print(0)
print(1)
sys.exit(0)
a= (optimal_sequence(n))
print(len(a)-1)
for x in reversed(a):
print(x,end=" ")
I would use a breadth first search for number 1 starting from number n. Keep track of the numbers that were visited, so that the search backtracks on already visited numbers. For visited numbers remember which is the number you "came from" to reach it, i.e. the next number in the shortest path to n.
In my tests this code runs faster than yours:
from collections import deque
def findOperations(n):
# Perform a BFS
successor = {} # map number to next number in shortest path
queue = deque() # queue with number pairs (curr, next)
queue.append((n,None)) # start at n
while True:
curr, succ = queue.popleft()
if not curr in successor:
successor[curr] = succ
if curr == 1:
break
if curr%3 == 0: queue.append((curr//3, curr))
if curr%2 == 0: queue.append((curr//2, curr))
queue.append((curr-1, curr))
# Create list from successor chain
result = []
i = 1
while i:
result.append(i)
i = successor[i]
return result
Call this function with argument n:
findOperations(n)
It returns a list.
I write project in Python3, which is advanced calculator. It consist of two modules: science calculator and basic calculator. I have a problem with second one. I want to create an input, which doesn't demand spaces between numbers and mathematical symbols. I have no idea, how to do this.
Can you help?
I attached only basic one's part of code, because science module import function from many of my different files.
from os import system
zbior = input().split(" ")
liczby = []
dzialania = []
if zbior[0] == "-" or zbior[0] == "+":
for i in range(1, len(zbior), 2):
try:
zbior[i] = float(zbior[i])
except ValueError:
print("Pamiętaj o poprawnym wprowadzeniu działania (odzziel liczby spacją), zobacz instrukcję.")
# calls the function which loops back code
elif zbior[0]=="m":
#calls menu function from differnet file
print("menu")
elif zbior[0] == "+" or str(zbior[0])[0] in "0123456789":
for i in range(0, len(zbior), 2):
try:
zbior[i] = float(zbior[i])
except ValueError:
print("Pamiętaj o poprawnym wprowadzeniu działania (odzziel liczby spacją), zobacz instrukcję.")
# calls the function which loops back code
else:
print("Pamiętaj o poprawnym wprowadzeniu działania, zobacz instrukcję.")
# calls the function which loops back code
if zbior[0] == "-" or zbior[0] == "+":
for znak in zbior:
if zbior.index(znak) % 2 != 0:
liczby.append(znak)
else:
dzialania.append(znak)
else:
for znak in zbior:
if zbior.index(znak) % 2 == 0:
liczby.append(znak)
else:
dzialania.append(znak)
ind = 0
suma = liczby[0]
while (ind+1) <= (len(dzialania)):
if dzialania[ind] == "+":
suma += liczby[ind+1]
if dzialania[ind] == "-":
suma -= liczby[ind + 1]
if dzialania[ind] == "*":
suma = suma*liczby[ind+1]
if dzialania[ind] == "/":
if liczby[ind+1] == 0:
print("""Pamiętaj cholero, nie dziel przez zero!!!""")
system('cls')
# calls the function which loops back code
else:
suma = suma/liczby[ind + 1]
if dzialania[ind] == "%":
if liczby[ind+1] == 0:
print("""Pamiętaj cholero, nie dziel przez zero!!!""")
system('cls')
#calls the function which loops back code
else:
suma = suma % liczby[ind + 1]
ind += 1
print(suma)
I don't know what some of the words in your script mean, but if I wanted to input something like 2+2 and get ["2", "+", "2"] I would do something like this:
zbior = [x for x in list(input()) if x != " "]
list(input()) splits every character in the input and if x != " " makes sure that whitespaces in the input are ignored.
Example:
>>> zbior = [x for x in list(input()) if x != " "]
1+2*3+4
>>> zbior
['1', '+', '2', '*', '3', '+', '4']
A simple list with skipping spaces then following those characters will work well.
For now.
Once you get into more complex expressions you'll have a lot of problems, write a proper mathematical expression evaluator instead. That is, if you really mean advanced calculator.
Consider following this guide: https://ruslanspivak.com/lsbasi-part1/
By part 6 you'll have a calculator that can evaluate ANY input that has less than a thousand ( left parentheses before they are closed off by ), Python has recursion depth of 1000, it can be increased, but there's a limit for a reason.
What I mean by that, is that it will be fine with an expression that has "(" * 999 before the first ) ever occurs, but I wouldn't expect anyone to write such monstrocity unless they are willing to spend next 3 years thinking about an expression or write a mathematical expression generator which is inverse of this. TL;DR - practically, this thing can evaluate anything you'd ever wish for. Advanced calculator for sure.
If you'll like it, you can even continue following it and make your own interpreter, it's slow, and if you want different syntax you'll have to sit for a bit and think about it, but I think it's worth doing at least once in your life.
I am trying to iterate over a sequence of numbers. I have this:
from itertools import islice, count
handle = int(input("Please enter a number:")
handler = str(handle)
parameter = []
for i in handler:
parameter.append(i)
print(parameter) #This was for debugging
revised = parameter(count(1[2])) #I'm not sure I'm using the correct syntax here, the purpose is to make revised == parameter[0] and parameter[2]
Ultimately, what I am trying to achieve is to take a sequence of numbers or two, and compare them. For instance, if i[0] == i[1] + i [2] I want to return True, or for that matter if i[0] == i[1] - i[2]. I want the program to iterate over the entire sequence, checking for these types of associations, for instance, 23156 would == true because 2*3 = 6, 2+3 = 5, 5+1 = 6, 2+3+1=6; etc. It's strictly for my own purposes, just trying to make a toy.
When I utilize
revised = parameter(count(1[2])
I am getting an error that says builtins. TYPEERROR, type int is not subscriptable but I explicitly turned the integer input into a string.
Albeit unclear, what you have attempted to describe is hard to explain. It appears to be akin to a Running Total but with restrictions and of various operations, i.e. addition, subtraction and products.
Restrictions
The first two numbers are seeds
The following numbers must accumulate by some operation
The accumulations must progress contiguously
Code
import operator as op
import itertools as it
def accumulate(vals):
"""Return a set of results from prior, observed operations."""
adds = set(it.accumulate(vals)) # i[0] == i[1] + i[2]
muls = set(it.accumulate(vals, op.mul)) # i[0] == i[1] * i[2]
subs = {-x for x in it.accumulate(vals, func=op.sub)} # i[0] == i[1] - i[2]
#print(adds, muls, subs)
return adds | muls | subs
def rolling_acc(vals):
"""Return accumulations by sweeping all contiguous, windowed values."""
seen = set()
for i, _ in enumerate(vals):
window = vals[i:]
if len(window) >= 3:
seen |= accumulate(window)
return seen
def is_operable(vals):
"""Return `True` if rolling operations on contiguous elements will be seen."""
s = str(vals)
nums = [int(x) for x in s]
ahead = nums[2:]
accums = rolling_acc(nums)
#print(ahead, accums)
return len(set(ahead) & accums) == len(ahead)
Tests
assert is_operable(23156) == True
assert is_operable(21365) == False # {2,3} non-contiguous
assert is_operable(2136) == True
assert is_operable(11125) == True