I have an exercise at school where we have to use the sys module to read a script file that contains instructions for the turtle module.
The script file is a .trtl file.
It contains the following info, formatted as below:
Walk
100
Turn
90
Walk
50
Turn
90
Walk
100
Turn
90
Walk
50
I have tried this code:
import sys
import turtle
for idx, line in enumerate(sys.stdin):
move = 0
while (idx % 2) == 0:
move = line
while (idx % 2) != 0:
if line == "Walk":
forward(move)
elif line == "Turn":
left(move)
when I try running this code with stdin from the script file, my terminal just goes to the next line without doing anything. I can see, that the program is running, and can KeyboardInterrupt it, but no window appears.
Any help would be greatly appreciated!
Your issue stems from two main problems:
Reading a line from a file will read the ENTIRE line, including the new line character at the end. Using .rstrip() method will remove that.
Reading a line from a file reads a string. You have to coerce it to the type that you need. For example, when you read the line 100, you are reading in 4 bytes: '1', '0' '0' '\n', not the number 100. You will need to add an int() coercion as well as strip the trailing \n to these lines.
Read up on the difference between an if and a while statement. An if statement will check the logical value of its argument, and decide whether or not to execute the following block of code. A while loop will loop through the code as long as the logical statement is truthy.
There are several other issues with your code, which I will indicate in comments.
Fixing your code:
import sys
import turtle
for idx, line in enumerate(sys.stdin):
#Strip trailing character
line = line.rstrip()
#Change if to while
if (idx % 2) == 0:
#Coerce value to int instead of string
move = int(line)
# idx % 2 will either be 0 or not 0, no need to check twice.
# If it is not 0, then this else statement will run
else:
#Now that line has been stripped of trailing chars, we can check
if line == "Walk":
forward(move)
#Alternately, we can use
# if line.startswith("Walk"):
# and not have to do an rstrip
elif line == "Turn":
left(move)
For fun, an alternative to #blackbrandt's detailed solution (+1) that, although terse, is also more easily expanded to additional monadic operators:
import sys
import turtle
commands = {'Walk': turtle.forward, 'Turn': turtle.left}
for command, argument in zip(sys.stdin, sys.stdin):
if method := commands.get(command.rstrip()):
method(int(argument))
turtle.exitonclick()
Related
I am surprising, I am using python to slice a long DNA Sequence (4699673 character)to a specific length supstring, it's working properly with a problem in result, after 71 good result \n start apear in result for few slices then correct slices again and so on for whole long file
the code:
import sys
filename = open("out_filePU.txt",'w')
sys.stdout = filename
my_file = open("GCF_000005845.2_ASM584v2_genomic_edited.fna")
st = my_file.read()
length = len(st)
print ( 'Sequence Length is, :' ,length)
for i in range(0,len(st[:-9])):
print(st[i:i+9], i)
figure shows the error from the result file
please i need advice on that.
Your sequence file contains multiple lines, and at the end of each line there is a line break \n. You can remove them with st = my_file.read().replace("\n", "").
Try st = re.sub('\\s', '', my_file.read()) to replace any newlines or other whitespace (you'll need to add import re at the top of your script).
Then for i in range(0,len(st[:-9]),9): to step through your data in increments of nine characters. Otherwise you're only advancing by one character each time: that's why you can see the diagonal patterns in your output.
I'm trying override my last print with a new line but I can't clear the last line.
I thought that flush would clear the line, but I can't see it has any effect.
import time
s = "qwertyuiopåasdfghjklæøzxccvbnm"
for num in range(len(s)):
print("\r{}".format(str[:len(s)-num]), end="", flush=True)
time.sleep(.1)
Here in my example, I end up with the output:
qwertyuiopåasdfghjklæøzxccvbnm
But wanted the output to be "q" only.
If the next print is smaller than the first line I can still see the end of the last line.
I could just override the first line with spaces, but I don't like that because if I then resize the console, it will shift everything around.
Is there anyway to really clear the last line and only the last line?
a solution that works both in linux and windows would be great.
Thanks.
You can use format to pad the string with whitespace, which will overwrite the old text.
import time
s = "qwertyuiopåasdfghjklæøzxccvbnm"
spacer = '\r{{:{}}}'.format(len(s)) # '\r{:30}' for this s
for num in range(len(s), 0, -1):
print(spacer.format(s[:num]), end='')
time.sleep(.1)
print()
You can read more about the Format Specification Mini-Language here
A more reusable solution could be:
from os import get_terminal_size
def rprint(*args, **kwargs):
try:
cols, rows = get_terminal_size()
except OSError:
# If get_terminal_size is not supported, override with whitespaces is not needed.
cols, rows = (1, 1)
# Override the line with whitespace and return cursor(-1 because of cursor size)
print("\r{:>{}}".format("", cols-1), end="\r")
print(*args, **{**kwargs, **{"end": "", "flush": True}})
if __name__ == '__main__':
import time
s = "qwertyuiopåasdfghjklæøzxccvbnmq"
# I want to end the loop with "q", not an empty string.
for num in range(len(s)):
rprint(s[:len(s) - num])
time.sleep(.1)
rprint("Override last line again")
Tested only in python 3.5+
But does fail, if the last printed line was larger than the terminal width.
I don't know if there is some way to get the last printed line to stdout? If there is then it would be possible to count the length of that line instead of get_terminal_size.
I have a file named sample.txt which looks like below
ServiceProfile.SharediFCList[1].DefaultHandling=1
ServiceProfile.SharediFCList[1].ServiceInformation=
ServiceProfile.SharediFCList[1].IncludeRegisterRequest=n
ServiceProfile.SharediFCList[1].IncludeRegisterResponse=n
Here my requirement is to remove the brackets and the integer and enter os commands with that
ServiceProfile.SharediFCList.DefaultHandling=1
ServiceProfile.SharediFCList.ServiceInformation=
ServiceProfile.SharediFCList.IncludeRegisterRequest=n
ServiceProfile.SharediFCList.IncludeRegisterResponse=n
I am quite a newbie in Python. This is my first attempt. I have used these codes to remove the brackets:
#!/usr/bin/python
import re
import os
import sys
f = os.open("sample.txt", os.O_RDWR)
ret = os.read(f, 10000)
os.close(f)
print ret
var1 = re.sub("[\(\[].*?[\)\]]", "", ret)
print var1f = open("removed.cfg", "w+")
f.write(var1)
f.close()
After this using the file as input I want to form application specific commands which looks like this:
cmcli INS "DefaultHandling=1 ServiceInformation="
and the next set as
cmcli INS "IncludeRegisterRequest=n IncludeRegisterRequest=y"
so basically now I want the all the output to be bunched to a set of two for me to execute the commands on the operating system.
Is there any way that I could bunch them up as set of two?
Reading 10,000 bytes of text into a string is really not necessary when your file is line-oriented text, and isn't scalable either. And you need a very good reason to be using os.open() instead of open().
So, treat your data as the lines of text that it is, and every two lines, compose a single line of output.
from __future__ import print_function
import re
command = [None,None]
cmd_id = 1
bracket_re = re.compile(r".+\[\d\]\.(.+)")
# This doesn't just remove the brackets: what you actually seem to want is
# to pick out everything after [1]. and ignore the rest.
with open("removed_cfg","w") as outfile:
with open("sample.txt") as infile:
for line in infile:
m = bracket_re.match(line)
cmd_id = 1 - cmd_id # gives 0, 1, 0, 1
command[cmd_id] = m.group(1)
if cmd_id == 1: # we have a pair
output_line = """cmcli INS "{0} {1}" """.format(*command)
print (output_line, file=outfile)
This gives the output
cmcli INS "DefaultHandling=1 ServiceInformation="
cmcli INS "IncludeRegisterRequest=n IncludeRegisterResponse=n"
The second line doesn't correspond to your sample output. I don't know how the input IncludeRegisterResponse=n is supposed to become the output IncludeRegisterRequest=y. I assume that's a mistake.
Note that this code depends on your input data being precisely as you describe it and has no error checking whatsoever. So if the format of the input is in reality more variable than that, then you will need to add some validation.
I'm writing an arcanoid game in python on windows console and what bothers me is annoying blinking after every iteration of "displaying" loop. Does anyone have any idea how to reduce it? This is part of the code:
#-*- coding: UTF-8 -*-
import time
import os
clear = lambda: os.system('cls')
def gra():
koniec='0'
while koniec!='1':
for i in range(4):
for j in range(10):
print '[___]',
print '\n',
for i in range(10):
print '\n'
for i in range(10):
print ' ',
print '~~~~~~~~~~'
time.sleep(0.1)
clear()
gra()
There is a limit to what you can do, but gathering everything into 1 big string and then printing once between screen clears is better than a number of small prints in a loop. Run the following code and look how much better the second half of the program runs than the first half:
import time, os, random
def display1(chars):
os.system('cls')
for row in chars:
print(''.join(row))
def display2(chars):
os.system('cls')
print('\n'.join(''.join(row) for row in chars))
chars = []
for i in range(40):
chars.append(["-"]*40)
for i in range(100):
r = random.randint(0,39)
c = random.randint(0,39)
chars[r][c] = "X"
time.sleep(0.1)
display1(chars)
os.system('cls')
time.sleep(1)
chars = []
for i in range(40):
chars.append(["-"]*40)
for i in range(100):
r = random.randint(0,39)
c = random.randint(0,39)
chars[r][c] = "X"
time.sleep(0.1)
display2(chars)
On Edit: You can combine these ideas with the excellent idea of #GingerPlusPlus to avoid cls. The trick is to print a large number of backspaces.
First -- write your own version of cls:
def cls(n = 0):
if n == 0:
os.system('cls')
else:
print('\b'*n)
The first time it is called -- pass it zero and it just clear the screen.
The following function pushes a character array to the command window in one big print and returns the number of characters printed (since this is the number of backspaces needed to reposition the cursor):
def display(chars):
s = '\n'.join(''.join(row) for row in chars)
print(s)
return len(s)
Used like thus:
chars = []
for i in range(40):
chars.append(["-"]*40)
for i in range(100):
n = 0
r = random.randint(0,39)
c = random.randint(0,39)
chars[r][c] = "X"
time.sleep(0.1)
cls(n)
n = display(chars)
when the above code is run, the display changes smoothly with virtually no flicker.
You could do:
rows_full=row_count+2
print("\033[F"*rows_full)
#print the screen again
The disadvantages are that you can't overwrite the very top bit of the console, and have to know how many rows have been printed. But knowing the row amount should be trivial when working with a fixed-rowed ASCII graphics game. It also isn't a CLS, it just moves you to the top.
Oh, the explanation! It uses the ANSI escape sequence F, which moves to the row above. It prints this many times, which puts you to the top of the screen. Also, you have to add 2 to the rowcount, otherwise the top rows will repeat.
PS: If anyone knows how to make it so that that method can reach the top part of the console, I'll give you some cookies.
I figured it out... You can use ANSI codes to move the cursor then clear the lines without any BLINK!
print('\033[4A\033[2K', end='')
\033[4A Moves the cursor 4 lines up (\033[{lines}A you can replace lines with however many you need)
\033[2K Clears all those lines without the screen blinking.
You can use it in a simple typewrite function that needs a constant message or a box around it like this:
from time import sleep
def typewrite(text: str):
lines = text.split('\n')
for line in lines:
display = ''
for char in line:
display += char
print(f'╭─ SOME MESSAGE OR SOMEONES NAME ────────────────────────────────────────────╮')
print(f'│ {display:74} │') # :74 is the same as ' ' * 74
print(f'╰────────────────────────────────────────────────────────────────────────────╯')
sleep(0.05)
print('\033[3A\033[2K', end='')
The only problem with this is that the top line is blinking. To fix this all we need to do is to add a empty line that is blinking so the user cant see it. We also move the cursor up from 3 to 4 lines.
def typewrite(text: str):
lines = text.split('\n')
for line in lines:
display = ''
for char in line:
display += char
print('')
print(f'╭─ SOME MESSAGE OR SOMEONES NAME ────────────────────────────────────────────╮')
print(f'│ {display:74} │') # :74 is the same as ' ' * 74
print(f'╰────────────────────────────────────────────────────────────────────────────╯')
sleep(0.05)
print('\033[4A\033[2K', end='')
To make this into your code just print your text and add a print('') at the start. Then use this print('\033[4A\033[2K', end='') but change the 4 to however many lines that you printed including the print(''). Then it should work without blinking. You can put print('\033[4B', end='') at the end which just moves the cursor back up.
If you want to hide the cursor you can use this gibberish or make the cursor the same color as the background:
import ctypes
if os.name == 'nt':
class _CursorInfo(ctypes.Structure):
_fields_ = [("size", ctypes.c_int),
("visible", ctypes.c_byte)]
def hide_cursor() -> None:
if os.name == 'nt':
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
ci.visible = False
ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))
def show_cursor() -> None:
if os.name == 'nt':
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
ci.visible = True
ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))
Note: All of this is still new to me so I am still testing this out to fully understand it.
anything really done with the windows console will blink if your clearing and rewriting the screen, unless you find something quite advanced I don't think you can remove the blinking
my only suggestion is to limit the clearing to when something actually changes.
or to use a tkinter text box instead of the cmd. If you want to use that idea I can help with it, although I mostly use tkinter for python 3.4
hopefully that helps!
I'm wondering, how can I count for example all "s" characters and print their number in a text file that I'm importing? Tried few times to do it by my own but I'm still doing something wrong. If someone could give me some tips I would really appreciate that :)
Open the file, the "r" means it is opened as readonly mode.
filetoread = open("./filename.txt", "r")
With this loop, you iterate over all the lines in the file and counts the number of times the character chartosearch appears. Finally, the value is printed.
total = 0
chartosearch = 's'
for line in filetoread:
total += line.count(chartosearch)
print("Number of " + chartosearch + ": " + total)
I am assuming you want to read a file, find the number of s s and then, store the result at the end of the file.
f = open('blah.txt','r+a')
data_to_read = f.read().strip()
total_s = sum(map(lambda x: x=='s', data_to_read ))
f.write(str(total_s))
f.close()
I did it functionally just to give you another perspective.
You open the file with an open("myscript.txt", "r") with the mode as "r" because you are reading. To remove whitespaces and \n's, we do a .read().split(). Then, using a for loop, we loop over each individual character and check if it is an 'S' or an 's', and each time we find one, we add one to the scount variable (scount is supposed to mean S-count).
filetoread = open("foo.txt").read().split()
scount = 0
for k in ''.join(filetoread):
if k.lower() == 's':
scount+=1
print ("There are %d 's' characters" %(scount))
Here's a version with a reasonable time performance (~500MB/s on my machine) for ascii letters:
#!/usr/bin/env python3
import sys
from functools import partial
byte = sys.argv[1].encode('ascii') # s
print(sum(chunk.count(byte)
for chunk in iter(partial(sys.stdin.buffer.read, 1<<14), b'')))
Example:
$ echo baobab | ./count-byte b
3
It could be easily changed to support arbitrary Unicode codepoints:
#!/usr/bin/env python3
import sys
from functools import partial
char = sys.argv[1]
print(sum(chunk.count(char)
for chunk in iter(partial(sys.stdin.read, 1<<14), '')))
Example:
$ echo ⛄⛇⛄⛇⛄ | ./count-char ⛄
3
To use it with a file, you could use a redirect:
$ ./count-char < input_file