How to add vectors to an ascii grid? - python

route001 = (3, 12, 'S', 'S', 'W', 'S', 'S', 'S', 'E', 'E', 'E', 'S', 'S', 'W',
'W', 'S', 'E', 'E', 'E', 'E', 'N', 'N', 'N', 'N', 'W', 'N', 'N',
'E', 'E', 'S', 'E', 'S', 'E', 'S', 'S', 'W', 'S', 'S', 'S', 'S',
'S', 'E', 'N', 'E', 'E')
start = [route001[0]] + [route001[1]]
directions = route001[2:]
coordinates = {"N": [0, 1], 'E': [1, 0], 'S': [0, -1], 'W': [-1, 0]}
vector_list = []
for d in directions:
dx, dy = coordinates[d]
start[0] += dx
start[1] += dy
vector_list.append(start.copy())
start_route = vector_list[0]
end_route = vector_list[-1]
My aim is to have route001 plotted on an ascii grid. The start of my above code turns N, E, S, W into vectors that are sequentially added to the variable vector_list i.e. if i print vector_list it returns [3, 12], [3,11] etc etc.
My question is how do i now get these vectors to display on a simple ascii grid such as?
for x in range(10):
print('- : ' * 10)
I would like it to either A) cycle through my vectors and plot them sequentially i.e. it displays the first vector on the screen, waits a second, then plots the second but not the first, then plots the third but not the second and so forth. B) the same as A but adds to the previous vector i.e. plots the first, then the first and second, then the first, second and third..
I think there might have to be some sort of loop to iterate through the ascii grid inputting the values from vector_list in order? I also think there is a much more elegant way to create the grid.
Please be patient, the above code has taken me a long time to write with a lot of help from SO and trial and error. Many thanks

Related

how to call a function to run on different data sets determined by user input in python?

I have routes (route001 and route002). The user will select either one. I then need the code to recognise what route has been selected and change the start and directions variables accordingly (in the code below start and directions has the data for route001). I then want to run the function called vectors() on the route data that was selected.
I am unsure of how to change start and directions depending on what route the user selected.
I am also unsure how to call the function vectors() on the route data. I am not confident either that I have created the function correctly.
Any help would be much appreciated as I am very new to this.
route001 = (3, 12, 'S', 'S', 'W', 'S', 'S', 'S', 'E', 'E', 'E', 'S', 'S', 'W',
'W', 'S', 'E', 'E', 'E', 'E', 'N', 'N', 'N', 'N', 'W', 'N', 'N',
'E', 'E', 'S', 'E', 'S', 'E', 'S', 'S', 'W', 'S', 'S', 'S', 'S',
'S', 'E', 'N', 'E', 'E')
route002 = (12, 11, 'W', 'W', 'S', 'S', 'S', 'W', 'W', 'N', 'N', 'N', 'W', 'W',
'W', 'S', 'S', 'S', 'S', 'E', 'E', 'S', 'W', 'W', 'W', 'W', 'N', 'N',
'W', 'W', 'S', 'S', 'S', 'S', 'E', 'E', 'E', 'S', 'E', 'S', 'E', 'S')
start = [route001[0]] + [route001[1]]
directions = route001[2:]
coordinates = {"N": [0, 1], 'E': [1, 0], 'S': [0, -1], 'W': [-1, 0]}
def vectors():
for d in directions:
dx, dy = coordinates[d]
start[0] += dx
start[1] += dy
if start[0] < 0 or start[0] > 12:
print('Error: This route goes outside the grid')
break
elif start[1] < 0 or start[1] > 12:
print('Error: This route goes outside the grid')
break
else:
print(start)
First, let the user input 1 or 2:
routeSelection = input("Press 1 or 2 to select a route")
Then asign start and directions accordingly:
if routeSelection == "1":
selectedRoute = route001
else if routeSelection == "2":
selectedRoute = route002
else #error
start = [selectedRoute [0]] + [selectedRoute [1]]
directions = selectedRoute [2:]
To then call the vectors function just put
vectors()
(Since the vector function uses the global start and directions, you dont need to pass any argument.)
OR:
You could also define the vectors() to take arguments and then call it by passing start and directions as arguments. To avoid confusion, you might want to rename the parameters inside the vectors function to something else:
# call of vectors
vectors(start, directions)
def vectors(startPoint, directionsList):
for d in directionsList:
dx, dy = coordinates[d]
startPoint[0] += dx
startPoint[1] += dy
...
If you decide to go this way AND you dont need the start and directions variable in the global scope, you could even directly call vectors() with the according arguments without assigning start and directions at all:
vectors([selectedRoute [0]] + [selectedRoute [1]], selectedRoute [2:])

Checking For Every Letter

I am trying to make code that breaks a password that I create, at first I got it to just make random answers to the password I created and eventually I would get the right one.
But I realized that if I could change the first letter of my answer and then when I had done all of the letters, change the second letter.
Ex: AA AB AC ... AY AZ BA BB BC.
I understand that I could make a loop to print every single letter, but how would I be able to change the first letter after I have gone through every letter.
I also need this to be able to break a password of any length so the loop would have to be able to change how many letters I need. I also need to get rid of the brackets and quotes in the output.
lower_upper_alphabet = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
while done == 0:
for i in range (int(passwordlen)):
for i in range(52):
for i in range(len(lower_upper_alphabet)):
characters2 = []
characters2.append(str(lower_upper_alphabet[next1]))
next1 += 1
print(characters2)
Output:
["A"]
["B"]
["C"]
["D"]
["E"]
["F"]
["G"]
["H"]
["I"]
["J"]
["K"]
["L"]
["M"]
["N"]
["O"]
["P"]
["Q"]
["R"]
["S"]
["T"]
["U"]
["V"]
["W"]
["X"]
["Y"]
["Z"]

Python script to generate a word with specific structure and letter combinations

I want to write a really short script that will help me generate a random/nonsense word with the following qualities:
-Has 8 letters
-First letter is "A"
-Second and Fourth letters are random letters
-Fifth letter is a vowel
-Sixth and Seventh letters are random letters and are the same
-Eighth letter is a vowel that's not "a"
This is what I have tried so far (using all the info I could find and understand online)
firsts = 'A'
seconds = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
thirds = ['a', 'e', 'i', 'o', 'u', 'y']
fourths = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
fifths = ['a', 'e', 'i', 'o', 'u', 'y']
sixths = sevenths = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
eighths = ['e', 'i', 'o', 'u', 'y']
print [''.join(first, second, third, fourth, fifth)
for first in firsts
for second in seconds
for third in thirds
for fourth in fourths
for fifth in fifths
for sixth in sixths
for seventh in sevenths
for eighth in eighths]
However it keeps showing a SyntaxError: invalid syntax after the for and now I have absolutely no idea how to make this work. If possible please look into this for me, thank you so much!
So the magic function you need to know about to pick a random letter is random.choice. You can pass a list into this function and it will give you a random element from that list. It also works with strings because strings are basically a list of chars. Also to make your life easier, use string module. string.ascii_lowercase returns all the letters from a to z in a string so you don't have to type it out. Lastly, you don't use loops to join strings together. Keep it simple. You can just add them together.
import string
from random import choice
first = 'A'
second = choice(string.ascii_lowercase)
third = choice(string.ascii_lowercase)
fourth = choice(string.ascii_lowercase)
fifth = choice("aeiou")
sixthSeventh = choice(string.ascii_lowercase)
eighth = choice("eiou")
word = first + second + third + fourth + fifth + sixthSeventh + sixthSeventh + eighth
print(word)
Try this:
import random
sixth=random.choice(sixths)
s='A'+random.choice(seconds)+random.choice(thirds)+random.choice(fourths)+random.choice(fifths)+sixth+sixth+random.choice(eighths)
print(s)
Output:
Awixonno
Ahiwojjy
etc
There are several things to consider. First, the str.join() method takes in an iterable (e.g. a list), not a bunch of individual elements. Doing
''.join([first, second, third, fourth, fifth])
fixes the program in this respect. If you are using Python 3, print() is a function, and so you should add parentheses around the entire list comprehension.
With the syntax out of the way, let's get to a more interesting problem: Your program constructs every (82255680 !) possible word. This takes a long time and memory. What you want is probably to just pick one. You can of course do this by first constructing all, then picking one at random. It's far cheaper though to pick one letter from each of firsts, seconds, etc. at random and then collecting these. All together then:
import random
firsts = ['A']
seconds = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
thirds = ['a', 'e', 'i', 'o', 'u', 'y']
fourths = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
fifths = ['a', 'e', 'i', 'o', 'u', 'y']
sixths = sevenths = ['a','b','c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
eighths = ['e', 'i', 'o', 'u', 'y']
result = ''.join([
random.choice(firsts),
random.choice(seconds),
random.choice(thirds),
random.choice(fourths),
random.choice(fifths),
random.choice(sixths),
random.choice(sevenths),
random.choice(eighths),
])
print(result)
To improve the code from here, try to:
Find a way to generate the "data" in a neater way than writing it out explicitly. As an example:
import string
seconds = list(string.ascii_lowercase) # you don't even need list()!
Instead of having a separate variable firsts, seconds, etc., collect these into a single variable, e.g. a single list containing each original list as a single str with all characters included.
This will implement what you describe. You can make the code neater by putting the choices into an overall list rather than have several different variables, but you will have to explicitly deal with the fact that the sixth and seventh letters are the same; they will not be guaranteed to be the same simply because there are the same choices available for each of them.
The list choices_list could contain sub-lists per your original code, but as you are choosing single characters it will work equally with strings when using random.choice and this also makes the code a bit neater.
import random
choices_list = [
'A',
'abcdefghijklmnopqrstuvwxyz',
'aeiouy',
'abcdefghijklmnopqrstuvwxyz',
'aeiouy',
'abcdefghijklmnopqrstuvwxyz',
'eiouy'
]
letters = [random.choice(choices) for choices in choices_list]
word = ''.join(letters[:6] + letters[5:]) # here the 6th letter gets repeated
print(word)
Some example outputs:
Alaeovve
Aievellu
Ategiwwo
Aeuzykko
Here's the syntax fix:
print(["".join([first, second, third])
for first in firsts
for second in seconds
for third in thirds])
This method might take up a lot of memory.

Print all possible strings of length k that can be formed from a set of n characters returns >n characters

Python novice here. The goal of the following Code is, to print all possible combinations to pair n characters of the set.
The Problem is that the following code gives an output, that also has more then n characters.
In the Following Code example n=3, but in the Output there are combinations with more then 3.
Code:
def printAllKLength(set, k):
n = len(set)
printAllKLengthRec(set, "", n, k)
def printAllKLengthRec(set, prefix, n, k):
if (k == 0) :
print(prefix)
return
for i in range(n):
newPrefix = prefix + set[i]
printAllKLengthRec(set, newPrefix, n, k-1)
if __name__ == "__main__":
print("First Test")
set1 = ['A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S','T','V','W','Y']
k = 3
printAllKLength(set1, k)
Output:
WNT
WNV
WNW
WNY
WPQA
WPQC
WPQD
WPQE
WPQF
WPQG
WPQH
WPQI
WPQK
WPQL
WPQM
WPQN
WPQPQ
WPQR
WPQS
WPQT
WPQV
WPQW
WPQY
WRA
The aim would be to generate strictly strings of length 3, so if anyone could point me in the right direction, I would be more than grateful.
I rewrote you functions a bit and stripped them to the essentials:
def printAllKLength(set, k):
printAllKLengthRec(set, "", k)
def printAllKLengthRec(set, string, k):
if len(string) == k:
print(string)
return
for c in set:
printAllKLengthRec(set, string + c, k)
return
if __name__ == "__main__":
print("First Test")
set1 = ['A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K',
'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'Y']
k = 3
printAllKLength(set1, k)
A little hint for next time, break you sample size down to for example len(set1) = 3. then it is far easier to debug and you don't get lost in your own code.
You can use Itertools' combinations function. It takes an iterable and the length of the combination as parameters.
import itertools
num_char = 3
my_set = {'A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'Y'}
combinations = itertools.combinations(my_set, num_char)
for i in combinations:
print("".join(i))

Efficient way of keeping numbers in order

This is a problem that could apply to any language, but I'll use python to show it.
Say you have a list of numbers, ls = [0,100,200,300,400]
You can insert an element at any index, but the elements must always stay in numerical order. Duplicates are not allowed.
For example, ls.insert(2, 150) results in ls = [0,100,150,200,300,400]. The elements are in the correct order, so this is correct.
However, ls.insert(3, 190) results in ls = [0,100,200,190,300,400]. This is incorrect.
For any index i, what is the best number x to use in ls.insert(i,x) to minimize the number of sorts?
My first intuition was to add half the difference between the previous and next numbers to the previous one. So to insert a number at index 3, x would equal 200 + (300-200), or 250. However this approaches the asymptote far too quickly. When the differences get too close to 0, I could restore the differences by looping through and changing each number to produce a larger difference. I want to choose the best number for x so to minimize the number of times I need to reset.
EDIT
The specific problem I'm applying this to is a iOS app with a list view. The items in the list are represented in a Set, and each object has an attribute orderingValue. I can't use an Array to represent the list (due to issues with cache-server syncing), so I have to sort the set each time I display the list to the user. In order to do this, the orderingValue must be stored on the ListItem object.
One additional detail is, due to the nature of the UI, the user is probably more likely to add an item to the top or bottom of the list rather than insert it in the middle.
You can generate sort keys indefinitely if you use strings rather than integers. That's because a lexicographical ordering of strings puts an infinite number of values between any two strings (as long as the larger isn't the smaller one followed by "a").
Here's a function to generate a lowercase string key between two other keys:
def get_key_str(low="a", high="z"):
if low == "":
low = "a"
assert(low < high)
for i, (a, b) in enumerate(zip(low, high)):
if a < b:
mid = chr((ord(a) + ord(b))//2) # get the character half-way between a and b
if mid != a:
return low[:i] + mid
else:
return low[:i+1] + get_key_str(low[i+1:], "z")
return low + get_key_str("a", high[len(low):])
It always returns a string s such that "a" <= low < s < high <= "z". "a" and "z" are never used themselves as keys, they're special values to indicate the boundaries of the possible results.
You'd call it with get_key_str([lst[i-1], lst[i]) to get a value to insert before the value at index i. You can insert and generate a value in one go with lst.insert(i, get_key_str(lst[i-1], lst[i])). Obviously though, the ends of the list need special handling.
The default values are set so that you can omit an argument to get a value to insert at the start or the end. That is, call get_key_str(high=lst[0]) to get a value to put at the start of your list or get_key_str(lst[-1]) to get a value to append to at the end. You can also explicitly pass "a" as low or "z" as high, if that's easier. With no arguments, it will return "m", which is a reasonable first value to put in an empty list.
It's possible that you could tune this a bit to give shorter keys when you're mostly adding at the start or end, but that would be a bit more complicated. This version should have its keys grow roughly evenly if you're inserting randomly.
Here's an example of doing some random inserts:
>>> import random
>>> lst = []
>>> for _ in range(10):
index = random.randint(0, len(lst))
print("inserting at", index)
if index == 0:
low = "a"
else:
low = lst[index-1]
if index == len(lst):
high = "z"
else:
high = lst[index]
lst.insert(index, get_key_str(low, high))
print(lst)
inserting at 0
['m']
inserting at 1
['m', 's']
inserting at 2
['m', 's', 'v']
inserting at 2
['m', 's', 't', 'v']
inserting at 2
['m', 's', 'sm', 't', 'v']
inserting at 0
['g', 'm', 's', 'sm', 't', 'v']
inserting at 3
['g', 'm', 's', 'sg', 'sm', 't', 'v']
inserting at 2
['g', 'm', 'p', 's', 'sg', 'sm', 't', 'v']
inserting at 2
['g', 'm', 'n', 'p', 's', 'sg', 'sm', 't', 'v']
inserting at 3
['g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v']
And here's how it behaves if we then do a bunch of inserts at the start and end:
>>> for _ in range(10):
lst.insert(0, get_key_str(high=lst[0])) # start
lst.insert(len(lst), get_key_str(low=lst[-1])) # end
print(lst)
['d', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x']
['b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y']
['am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym']
['ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys']
['ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv']
['ab', 'ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv', 'yx']
['aam', 'ab', 'ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv', 'yx', 'yy']
['aag', 'aam', 'ab', 'ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv', 'yx', 'yy', 'yym']
['aad', 'aag', 'aam', 'ab', 'ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv', 'yx', 'yy', 'yym', 'yys']
['aab', 'aad', 'aag', 'aam', 'ab', 'ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv', 'yx', 'yy', 'yym', 'yys', 'yyv']
So at the start you may end up with keys prefixed by as, and at the end you'll get keys prefixed by ys.
As far as the 'best' value is concerned, it is always going to be halfway through the previous and the next element. And it is going to reach the asymptote.
One way to delay arrival at the asymptote if there are repeated insertions at a particular index is to decrement the previous and increment the next value (I'm assuming you are allowed to do this) every time you perform the insert.
So, for ls.insert(2,150), after insertion
ls[1] = ls[1] - (ls[1] - ls[0])/2
ls[3] = ls[3] + (ls[4] - ls[3])/2
For every other insertion, this rule will hold, and assuming insertions are at random indices, you would have a fair amount of time before you need to increase each number's value.
Also, the moment you encounter two adjacent numbers with a difference of 1, you would, of course, have to loop through the numbers and increase them.

Categories

Resources