Map for text based game - python

this is supposed to make a map for a text based game which works great until I add more than one point to the map when I add a second point to it, it makes the length of the map 2x bigger than needed
this is example with 2 points
mapS = [5,5] ##Size of the map
line = ""
objects = dict()
numx = 0
numy = 0
def mapSize(x,y):
mapS = [x,y]
def addObject(name, x, y, symbol):
globals()[name] = [x,y, symbol]
objects[name] = [x,y, symbol]
addObject("House", 2,3, "H") ##############FIRST POINT
addObject("Cabin", 3,4, "C") ##############SECOND POINT
for y in range(mapS[1]):
numy += 1
for x in range(mapS[0]):
numx += 1
for place in objects:
if objects[place][0] == numx:
if objects[place][1] == numy:
line += objects[place][2]
else:
line += "*"
else:
line += "*"
print(line)
line =""
numx = 0
numy = 0

The actual problem is that, for each y and each x, you're printing one character for each object:
for y in range(mapS[1]):
numy += 1
for x in range(mapS[0]):
numx += 1
for place in objects:
if objects[place][0] == numx:
if objects[place][0] == numy:
line += objects[place][2]
else:
line += "*"
else:
line += "*"
So, if you have 2 objects, you'll print 2 characters at each x, y point; if you have 6 objects, you'll print 6 characters at each x, y point.
What you want to do is only print 1 character at each x, y point. For example:
for y in range(mapS[1]):
numy += 1
for x in range(mapS[0]):
numx += 1
for place in objects:
if objects[place][0] == numx and objects[place][0] == numy:
line += objects[place][2]
break
else:
line += "*"
This goes through the objects until it finds the first one that matches that position, and adds only that one object's character, and stops searching with break. Then, only if it gets to the end of the loop without breaking (that's what an else clause on a for statement means), it adds a * instead.
You have a number of other problems here:
mapSize doesn't actually change mapS; you need a global mapS statement.
You're comparing both numx and numy to objects[place][0]. You almost certainly wanted to compare numy to objects[place][1]. One nice way to do this all at once is: if objects[place][:2] == [numx, numy]:.
Your numx and numy are 1-based. Did you want that? If so, it would make your intention more explicit—and a whole lot simpler—to just use numx == x+1 instead of keeping track of it separately from x but in such a way that it always ends up the same as x+1. If not, just use x itself.
The globals()[name] = is a bad idea. Since you don't make any use of it, the simplest way to fix that is to just remove that line.
It's a lot simpler to create things like line at the top of the loop, instead of creating them outside the loop and then re-creating them at the bottom of the loop.
So, putting it all together:
mapS = [5, 5]
objects = {}
def mapSize(x, y):
global mapS
mapS = [x, y]
def addObject(name, x, y, symbol):
objects[name] = [x, y, symbol]
addObject("House", 2, 3, "H") ##############FIRST POINT
addObject("Cabin", 3, 4, "C") ##############SECOND POINT
for y in range(mapS[1]):
line = ""
numy = y+1
for x in range(mapS[0]):
numx = x + 1
for place in objects:
if objects[place][:2] == [numx, numy]:
line += objects[place][2]
break
else:
line += "*"
print(line)

Related

Need some help on a function

Write a function named one_frame that takes one argument seq and performs the tasks specified below. The argument seq is to be a string that contains information for the bases of a DNA sequence.
a → The function searches given DNA string from left to right in multiples of three nucleotides (in a single reading frame).
b → When it hits a start codon ATG it calls get_orf on the slice of the string beginning at that start codon.
c → The ORF returned by get_orf is added to a list of ORFs.
d → The function skips ahead in the DNA string to the point right after the ORF that we just found and starts looking for the next ORF.
e → Steps a through d are repeated until we have traversed the entire DNA string.
The function should return a list of all ORFs it has found.
def one_frame(seq):
start_codon = 'ATG'
list_of_codons = []
y = 0
while y < len(seq):
subORF = seq[y:y + 3]
if start_codon in subORF:
list_of_codons.append(get_orf(seq))
return list_of_codons
else:
y += 3
one_frame('ATGAGATGAACCATGGGGTAA')
The one_frame at the very bottom is a test case. It is supposed to be equal to ['ATGAGA', 'ATGGGG'], however my code only returns the first item in the list.
How could I fix my function to also return the other part of that list?
You have several problems:
You have return list_of_codons inside the loop. So you return as soon as you find the first match and only return that one. Put that at the end of the function, not inside the loop.
You have y += 3 in the else: block. So you won't increment y when you find a matching codon, and you'll be stuck in a loop.
You need to call get_orf() on the slice of the string starting at y, not the whole string (task b).
Task d says you have to skip to the point after the ORF that was returned in task b, not just continue at the next codon.
def one_frame(seq):
start_codon = 'ATG'
list_of_orfs = []
y = 0
while y < len(seq):
subORF = seq[y:y + 3]
if start_codon = subORF:
orf = get_orf(seq[y:])
list_of_orfs.append(orf)
y += len(orf)
else:
y += 3
return list_of_orfs
one_frame('ATGAGATGAACCATGGGGTAA')
You have a number of problems in this code, as identified in the comments. I think this does what you are actually supposed to do:
def one_frame(seq):
start_codon = 'ATG'
list_of_codons = []
y = 0
while y < len(seq):
if seq[y:y+3] == start_codon:
orf = get_orf(seq[y:])
list_of_codons.append(orf)
y += len(orf)
else:
y += 3
return list_of_codons
one_frame('ATGAGATGAACCATGGGGTAA')
Try splitting seq into codons instead:
def one_frame(seq):
shift = 3
codons = [seq[i:i+shift] for i in range(0, len(seq), shift)]
start_codon = "ATG"
orf_list = []
for codon in codons:
if codon == start_codon:
orf_list += [get_orf(codon)]
return orf_list
seq = 'ATGAGATGAACCATGGGGTAA'
one_frame(seq)
Slightly different approach but as I know nothing about DNA sequencing this may not make sense. Here goes anyway:
def one_frame(seq):
start_codon = 'ATG'
list_of_codons = []
offset = 0
while (i := seq[offset:].find(start_codon)) >= 0:
offset += i
list_of_codons.append(get_orf(seq[offset:]))
offset += len(list_of_codons[-1])
return list_of_codons
In this way the find() starts searching from the beginning of the sequence initially but subsequently only from the end of any previous codon

Find occurrence of a string in another string

Details:
There are two strings x and y.
Count the number of occurrence of y in x as follows:
Length of y is 3.
Increment the "count" value when y == x[i] x[i+2] x[i+4]
Example:
x = "aabbcc"
y = "abc"
output: 2
My Code:
def solution(x, y):
i, count = 0, 0
j = i + 2
k = i + 4
while i+4 < len(x):
cur = x[i]
while i < len(x) and i != j:
i += 1
while i < len(x) and i != k:
i += 1
count += 1
return count
solution(x, y)
I am getting count = 1. It should give count = 2
There's a couple of logic errors in your code.
The problem happens here:
while i < len(x) and i != j:
i += 1
res.append(x[i])
You keep increasing i until it is either len(x) or greater, or until it is the same as j. But since you set j to be 2 at the start (and never update it), it will simply end up setting i to len(x). And x[i] will thus fail, since x[len(x)] tries to index an element just outside x.
However, there's a few more remarks to make:
you collect what you find in res, but really only want a number (e.g. 2) as a result
you define count but don't use it
you track the coordinates in the string in three separate variables (i, j, k) and have a lot of logic to increment the first, but really all you need is to step through the string one position at a time, and look at the offsets directly
Given all that and the problem description, you were probably going for something like this:
x = "aabbcc"
y = "abc"
def solution(x, y):
i, count = 0, 0
while i + 4 < len(x):
if (x[i], x[i+2], x[i+4]) == (y[0], y[1], y[2]):
count += 1
i += 1
return count
print(solution(x, y))
However, Python has some cleverness that would make it even simpler (or at least shorter):
def solution(x, y):
count = 0
for i in range(len(x)-4):
if x[i:i+5:2] == y: # slicing with a stride of two, instead of direct indexing
count += 1
return count
Or even:
def solution(x, y):
return len([x for i in range(len(x)-4) if x[i:i+5:2] == y])
But that's favouring brevity over readability a bit too much, I feel.
A generator expression solution, taking advantage of True/False == 1/0 in a numeric context:
def solution(x, y):
return sum(y == x[i:i+5:2] for i in range(len(x)-4))
Increment the "count" value when y == x[i] x[i+2] x[i+4]
This is the same as simply creating the string consisting of x[0], x[2], x[4]... (every even-numbered character) and the string consisting of x[1], x[3], x[5]... (every odd-numbered character); counting the occurrences of y in each; and adding those two results together.
Creating the strings is trivial, and a common duplicate. Counting occurrences of a substring is also well-trodden ground. Putting these tools together:
def spread_substrings(needle, haystack):
even_haystack = haystack[::2]
odd_haystack = haystack[1::2]
return even_haystack.count(needle) + odd_haystack.count(needle)

traversing through a list using recursion

So I am new to recursion and I am trying to make a program where you can enter a list and python tests each integer (lets say 9 for example) and sees if the integer following it is doubled. So if I entered a list of 2 4 8 16 32, would return 4, and -5 -10 0 6 12 9 36, would return 2 because -5 followed by -10 is one and 6 followed by 12 is the second. This is the code I have so far. I feel like I am very close. but just a few thing stand in my way. Any help would be great!
L = []
def countDouble(L):
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
print(y[1])
print(y[0])
count = 0
y[0] += y[0]
# unsure of how to multiple y[0] by 2
if y[0]*2 == y[1]:
count += 1
else:
count += 0
#how would I traverse through the rest of the entered list using recursion?
print(count)
countDouble(L)
If you want/need to solve it using recursion, the following will do the trick:
def count_sequential_doubles(li, count=0):
return count_sequential_doubles(li[1:], count + int(li[0] * 2 == li[1])) if len(li) > 1 else count
I would suggest this recursive way:
def countDouble(L):
count = 0
if len(L) == 1:
return count
else:
if int(L[0])*2 == int(L[1]):
count += 1
return count + countDouble(L[1:])
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = countDouble(y)
print(count)
I urge you to read the entire answer, but in case you are not interested in tips, notes and the process of finding the solution, here are two solutions:
solution using recursion (not recommended):
x = input()
y = x.split(' ')
count = 0
def countDouble(i):
if(i+1 == len(y)):
return 'recursion ends here when'
if(int(y[i])*2==int(y[i+1])):
count += 1
countDouble(i+1)
countDouble(0)
print(count)
this solution just imitates a while loop:
solution using a while loop (recommended):
x = input()
y = x.split(' ')
count = 0
i = 0
while(i < len(y) - 1):
if(int(y[i]) * 2 == int(y[i+1])):
count += 1
i += 1
print(count)
Before I continue, here are a few tips and notes: (some of them will only make sense after)
I assume the 14 in your example is a typo
I didn't put the code in a function because it's not needed, but you can change it easily.
In your code, you are passing L as a parameter to the countDouble() function, but you don't use it. if you don't need a parameter don't pass it.
when splitting the input, the values of the list are still strings. so you have to invert them to integers (for instance, you can do that with the int() 'function') before comparing their values - otherwise multiplying by 2 will just repeat the string. for example: '13'*2 is the string '1313'
I don't know why you why you added y[0] to itself in line 9, but based on the code that comes after this would yield incorrect results, you don't need to change the elements in order to get their value multiplied by 2.
notice that in the else block, nothing has changed. adding 0 to the count doesn't change it. so you can remove the else block entirely
While it's possible to solve the problem in recursion, there's something else designed for these kind of problems: loops.
The problem is essentially repeating a simple check for every element of a list.
This is how I would arrive to a solution
so we want to run the following 'code':
if(y[0]*2 == y[1]):
count += 1
if(y[1]*2 == y[2]):
count += 1
if(y[2]*2 == y[3]):
count += 1
...
of course the computer doesn't understand what "..." means, but it gives us an idea to the pattern in the code. now we can do the following:
divide the extended 'code' into similar sections.
identify the variables in the pattern - the values that change between sections
find the starting values of all variables
find a pattern in the changes of each variable
find a breaking point, a condition on one of the variables that tells us we have reached the last repeating section.
here are the steps in this specific problem:
the sections are the if statements
the variables are the indexes of the elements in y we compare
the first index starts at 0 and the second at 1
both indexes increase by one after each if-statement
when the second index is bigger then the last index of y then we already checked all the elements and we can stop
so all is left is to set the needed variables, have a while loop with the breaking condition we found, and in the while loop have the general case of the repeating sections and then the changing of the variables.
so:
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = 0
# setting the starting values of the variables
index1 = 0
index2 = 1
# creating a loop with the breaking condition
while(index2 < len(y)):
# the general case of the repeated code:
if(int(y[index1]) * 2 == int(y[index2])):
count += 1
# changing the variables for the next loop
index1 += 1
index2 += 1
print(count)
We see that the index2 is just index1 + 1 at all time. so we can replace it like that:
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = 0
index1 = 0
while(index1 + 1 < len(y)):
if(int(y[index1]) * 2 == int(y[index1 + 1])):
count += 1
index1 += 1
print(count)
Note: You can use a for loop similarly to the while loop
So in summary, you can use recursion to solve the problem, but the recursion would just be imitating the process of a loop:
in each call, the breaking condition will be checked, the repeated code would run and the variables/parameters would change.
Hope you find this answer useful :)
Final edit: OP edited his example so my other code didnt apply
Some good questions people are asking, but in the spirit of helping, here's a recursive function that returns the count of all doubles.
def get_doubles_count_with_recursion(a_list, count, previous=None):
while a_list:
try:
first = previous if previous else a_list.pop(0)
next_item = a_list.pop(0)
except IndexError:
return count
if next_item / 2 == first:
count += 1
return get_doubles_count_with_recursion(a_list, count, next_item)
return count
a_list = [1, 3, 5, 10, 11, 14, 28, 56, 88, 116, 232, 464, 500]
doubles = get_doubles_count_with_recursion(a_list, 0)
print(doubles == 5)
Probably could clean it up a bit, but it's a lot easier to read than the other guy's ;)
If I'm reading your question right, you want a count of all pairs where the 2nd item is double the first. (and the 14 in the first list is a typo). In which case a simple function like this should do the job:
#a = [2,4,8,16,32]
a = [-5, -10, 0, 16, 32]
count = 0
for i, x in enumerate(a):
# Stop before the list overflows
if i < len(a) - 1:
# If the next element is double the current one, increment the counter
if a[i+1] == x * 2:
count = count + 1
else:
break
print(count)

Matplotlib connect scatterplot points with line

I read the question Matplotlib connect scatterplot points with line - Python but it doesn't work for me...
I tried to use plt.scatter(x, y) and after that plt.show(), but all that I see is a set of separated dots from each other.
I think, that problem consists in that I use a loop for generating each point on the plot and after that loop, I use plt.show().
All my code looks like this:
x = 0
y = 0
def eye_gaze1(a,b):
global x,y
image_plot1 = plt.imshow(image1)
for i in range(len(a)):
if stimulus_name[x+y+1] == '5_01.jpg' and a[x+y+1] != '-':
plt.scatter([a[x+y+1]], [b[x+y+1]]) #here I putting new point on the image_plot1 and this process repeats (something like 1000 times) before in my massive of data cycle will find '-' symbol
x += 1
else:
x += 1
break
plt.show() #final image
y += x
x = 0
j = 0
while j < 15: #just repeat this function for another cells in data-massive
eye_gaze1(col_values_X_right,col_values_Y_right)
j += 1
So, question is, how can I connect points?
If I try to use the comment of JohanC, I see this error: TypeError: ufunc 'sqrt' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
x = 0
y = 0
def eye_gaze1(a,b):
global x,y
image_plot1 = plt.imshow(image1)
for i in range(len(a)):
if stimulus_name[x+y+1] == '5_01.jpg' and a[x+y+1] != '-':
X_coordinates = list().append(a[x+y+1])
Y_coordinates = list().append(b[x+y+1])
x += 1
else:
x += 1
break
plt.scatter(X_coordinates, Y_coordinates, '-o')
plt.show()
y += x
x = 0
j = 0
while j < 15:
eye_gaze1(col_values_X_right,col_values_Y_right)
print(x)
print(y)
j += 1

Using variable to call element of list is returning "List index out of range"

I'm new to coding and have been having this problem for a bit, I've tried looking around and messing with the code but can't seem to find the problem as simple as the solution probably is.
My code is:
import random
import sys
import os
clear = lambda: os.system('cls')
clear()
filt = int(raw_input("What number do you want your results to be filtered by?"))
clear()
gorl = raw_input("Do you want to filter numbers greater or lower than %i?" %(filt))
clear()
ammvar = int(raw_input("How many variables do you want to filter?"))
clear()
y = ammvar
var_list_remainder = []
var_list = []
varnum = 1
while ammvar > 0:
var_list.append(int(raw_input("Variable %i:"%(varnum))))
varnum = varnum + 1
ammvar = ammvar - 1
clear()
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
if gorl == "greater":
x = 0
while y > 0:
if var_list[x] > filt:
var_list_remainder.append(var_list[x])
x = x + 1
y = y - 1
elif var_list[x] <= filt:
x = x + 1
y = y + 1
elif gorl == "lower":
x = 0
while y < 0:
if var_list[x] > filt:
var_list_remainder.append(var_list[x])
x = x + 1
y = y - 1
elif var_list[x] >= filt:
x = x + 1
y = y + 1
print(var_list_remainder)
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
If I run this and I get to input my variables then the following error occurs:
Traceback (most recent call last):
File "c:/Users/D/OneDrive/Documents/Intro To Python/GreaterOrLower.py", line 43, in
if var_list[x] > filt:
IndexError: list index out of range
The problem is you're trying to use y as an auxiliary variable to iterate through the list var_list (since it tells the loop when to stop) and it's not stoping the loop on time. I would change the way you iterate through var_list and use a simpler approach.
I only changed this bit of code:
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
if gorl == "greater":
for item in var_list: # item will take the value of each element in the list for each iteration
if item > filt: # we check if the item is greater
var_list_remainder.append(item) # we append it
elif gorl == "lower":
for item in var_list: # item will take the value of each element in the list for each iteration
if item < filt: # we check if the item is lower
var_list_remainder.append(item) # we append it
print(var_list_remainder)
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
I would change a few more things but those are not related to question.
Because y can be incremented, the while loop can run more than ammvar, thus x can grow bigger than the size of the list. When getting an item by an index bigger than the size of the list (minus one, because it is zero indexed) you get an exception.
Your algorithm is not clear enough to me for me to fix it.

Categories