I'm currently writing 2 programs in python that must play a number game against each other. One program picks a number between 1 and 100. Then the other attempts to guess what that number is. Each time the guesser gives it's guess, the chooser then replies with 'too big', 'too small', or 'you got it'. According to what the reply is the guesser adjusts its next guess accordingly.
Here's my code for the program that chooses:
import random
from guesser import g
guessCount = 0
number = random.randint(1, 100)
print("I'm thinking of a number between 1 and 100.")
outfile = open ('response.txt', 'w')
guess = 50
print (guess)
if guess < number:
print('Your guess is too low.')
switch = '1'
outfile.write (switch + '\n')
elif guess > number:
print('Your guess is too high.')
switch = '2'
outfile.write (switch + '\n')
else:
print('Correct, You guessed the number in', guessCount, 'guesses.')
switch = '3'
outfile.write (switch + '\n')
while guessCount < 8:
guess = g
print (guess)
guessCount += 1
if guess < number:
print('Your guess is too low.')
switch = '1'
outfile.write (switch + '\n')
elif guess > number:
print('Your guess is too high.')
switch = '2'
outfile.write (switch + '\n')
else:
print('Correct, You guessed the number in', guessCount, 'guesses.')
switch = '3'
outfile.write (switch + '\n')
break
outfile.close()
print('The number was',number)
And here's the code for the program that gives the guesses:
low = 1
high = 100
guess = 0
guessCounter = 0
infile = open ('response.txt', 'r')
switch = int (infile.readline())
def g (switch):
while switch != 3 and guessCounter < 8:
guess = (low+high)//2
guessCounter += 1
if switch == 1:
high = guess
elif switch == 2:
low = guess + 1
return guess
My main question is how to get the 2 programs to interact with eachother. I'm currently trying to use a method of having them communicate through a text file called response, but surely there's an easier way?
The main problem I'm having it seems is that when chooser tries to get the variable g from guesser it can't because there's no response currently in response.txt meaning switch = int ('')
Traceback (most recent call last): File
"C:\Users\Jash\Downloads\guesser.py", line 8, in
switch = int (infile.readline()) ValueError: invalid literal for int() with base 10: ''
And yes, they must be 2 separate programs. And it must be done in python.
It would be a lot easier to put both players in the same program.
If you really want to use 2, though, you can run them like this on unix or linux:
echo "" > somefile
tail -f somefile | program1 | program2 >> somefile
This will effectively pipe each program's output into the other's input. Of course anything you want to see should be printed to standard error.
You can open the child scripts from your main script like this:
from subprocess import Popen, PIPE
prog = Popen("child.py", shell=True, stdin=PIPE, stdout=PIPE)
prog.stdin.write("Message to child.py maybe from another child?\n")
print prog.stdout.read() #Response from child
prog.wait() # Wait for script to finish run next script
as mentioned by Matt Timmermans:
if it is not absolutely neccessary, put the whole logic into one program:
import random
def createNum():
return random.randint(1,101)
lastGuess = 0
randMin, randMax = 1, 101
def guessNum(sigmoidAdjustmentInt):
# sigmoidAdjustmentInt represents a number which is negative, equal to zero or positiv; e.g. [-1 / 0 / +1]
# 0 == no information about to big or to small number
# -1 == number has to be smaller this time
# 1 == number has to be bigger this time
# guess somehow; e.g. with random again
if sigmoidAdjustmentInt < 0:
randMax = lastGuess-1
elif 0 < sigmoidAdjustmentInt:
randMin = lastGuess+1
return random.randint(randMin,randMax)
def main():
secretNumber = createNum()
guessedCorrectly = False
triesCounter = 0
sigmoidAdjustmentInt = 0 # set here for the first call
while not guessedCorrectly:
triesCounter = 0
if guessNum(sigmoidAdjustmentInt) == secretNumber:
guessedCorrectly = True
break
# print here if too high or low
print("needed guesses: "+ triesCounter)
# do something else
please note that the random.randint(...)-calls of createNum and guessNum are only placeholders for your preferred implementations of it.
see also: random.randint
as for your question how to execute multiple scripts.
say you have 3 files:
a.py
b.py
c.py
you start a.py, it does something, calls b.py and after that calls c.py with the result.
you can do it this way:
# in a.py
import subprocess
args = ( # rebuild the commandline call of the file here; the following stands for the comandline command: python b.py
"python", # every whitespace in the cmd-command is a comma in this args-tuple
"b.py"
)
popen = subprocess.Popen(args, stdout=subprocess.PIPE)
popen.wait()
resultsOfB, errorsOfB = popen.communicate()
del popen
args = ( # this represents: python c.py someStringValueContainedInResultFromB
"python",
"c.py",
resultOfB # lets just say this var contains a string => if not convert it to one
)
popen = subprocess.Popen(args, stdout=subprocess.PIPE)
popen.wait()
resultsOfC, errorsOfC = popen.communicate()
# do something with the results of c.py
again: if you write all three of the files, consider to put them together into one. this method is good if you have to call third party software or something like that (e.g.:)
Create a third, referee program. Take two arguments - the names of the picker and the guesser programs. Have the referee program open read/write pipes to the two programs, and using either the subprocess or the pexpect module.
Related
So I made a very simple Auto-typer and want to be able to run it again or quit it.
All works perfectly fine but at the end the "ending = input()" doesnt let me type it just exits out of the programm. Any reason why?
import pyautogui
import time
import os
def clearConsole():
command = 'clear'
if os.name in ('nt', 'dos'): # If Machine is running on Windows, use cls
command = 'cls'
os.system(command)
break_loop = 1
while break_loop <= 1:
secs_inbetween_actions = float(input("""
Seconds between actions(should be float but int is also ok): """))
no_of_lines = int(input("""
How many Lines do you want to write?(Only int): """))
time_between_action = int(input("""
How long should the time between enter and writing be?: """))
lines = ""
print("""
Write your Text under this message (You have """ + str(no_of_lines) + """ line(s) to wite)
""")
for i in range(no_of_lines):
lines += input() + "\n"
print("-------------------------------------")
while time_between_action > 0:
time_between_action = time_between_action - 1
print('Time Left until writing -+==> ' + str(time_between_action))
time.sleep(1)
print("-------------------------------------")
pyautogui.typewrite(lines, interval=secs_inbetween_actions)
ending = input("If you want to use this aplication once again type 'y' + 'enter key' ,if not press the 'enter key': ")
if ending == "y":
break_loop = 1
clearConsole()
else:
break_loop += 1
This is a rather fun little problem. It occurs, as #Barmar notes, because pyautogui.typewrite() is writing to the console for you. I incorrectly thought that it was not happening when there was no delay between actions, which was a far more puzzling little problem.
In this case the solution is easy: add after your typewrite():
if lines:
input()
To absorb what has just been typed for you.
Let's say I want to pipe input to a Python program, and then later get input from the user, on the command line.
echo http://example.com/image.jpg | python solve_captcha.py
and the contents of solve_captcha.py are:
import sys
image_url = sys.stdin.readline()
# Download and open the captcha...
captcha = raw_input("Solve this captcha:")
# do some processing...
The above will trigger a EOFError: EOF when reading a line error.
I also tried adding a sys.stdin.close() line, which prompted a ValueError: I/O operation on closed file.
Can you pipe information to stdin and then later get input from the user?
Note: This is a stripped down, simplified example - please don't respond by saying "why do you want to do that in the first case," it's really frustrating. I just want to know whether you can pipe information to stdin and then later prompt the user for input.
There isn't a general solution to this problem. The best resource seems to be this mailing list thread.
Basically, piping into a program connects the program's stdin to that pipe, rather than to the terminal.
The mailing list thread has a couple of relatively simple solutions for *nix:
Open /dev/tty to replace sys.stdin:
sys.stdin = open('/dev/tty')
a = raw_input('Prompt: ')
Redirect stdin to another file handle when you run your script, and read from that:
sys.stdin = os.fdopen(3)
a = raw_input('Prompt: ')
$ (echo -n test | ./x.py) 3<&0
as well as the suggestion to use curses. Note that the mailing list thread is ancient so you may need to modify the solution you pick.
bash has process substitution, which creates a FIFO, which you can treat like a file, so instead of
echo http://example.com/image.jpg | python solve_captcha.py
you can use
python solve_capcha.py <(echo http://example.com/image.jpg)
You would open first argument to solve_capcha.py as a file, and I think that sys.stdin would still be available to read input from the keyboard.
Edit: if you're not using bash, you can use mkfifo to accomplish the same thing on any POSIX system:
mkfifo my_pipe
echo "http://example.com/image.jpg" > my_pipe
python solve_captcha.py my_pipe
The FIFO will block (wait without closing) for output.
You can close stdin and then reopen it to read user input.
import sys, os
data = sys.stdin.readline()
print 'Input:', data
sys.stdin.close()
sys.stdin = os.fdopen(1)
captcha = raw_input("Solve this captcha:")
print 'Captcha', captcha
Made this up to emulate raw_input(), since I had the same problem as you. The whole stdin and clear ugliness is simply to make it look pretty. So that you can see what you are typing.
def getInputFromKeyPress(promptStr=""):
if(len(promptStr)>0):
print promptStr
"""
Gets input from keypress until enter is pressed
"""
def clear(currStr):
beeString, clr="",""
for i in range(0,len(currStr)):
clr=clr+" "
beeString=beeString+"\b"
stdout.write(beeString)
stdout.write(clr)
stdout.write(beeString)
from msvcrt import kbhit, getch
from sys import stdout
resultString, userInput="", ""
while(userInput!=13):
if (kbhit()):
charG=getch()
userInput= ord(charG)
if(userInput==8):#backspace
resultString=resultString[:-1]
clear(resultString)
elif(userInput!=13):
resultString="".join([resultString,charG])
clear(resultString)
stdout.write(resultString)
if(userInput==13):
clear(resultString)
#print "\nResult:",resultString
return resultString.strip()
I updated #Bob's answer to support delete, ctrl + [left, right, home, end] keypresses and simplified the stdout clearing and rewriting.
def keypress_input(prompt_str=""):
"""
Gets input from keypress using `msvcrt` until enter is pressed.
Tries to emulate raw_input() so that it can be used with piping.
:param prompt_str: optional string to print before getting input
:type prompt_str: str
"""
from re import finditer
from msvcrt import getch
from sys import stdout
# print even if empty to create new line so that previous line won't be overwritten if it exists
print prompt_str
user_input = ""
curr_chars = []
cursor_pos = 0
backspace = 8
enter = 13
escape_code = 224
delete = 83
left = 75
right = 77
home = 71
end = 79
ctrl_left = 115
ctrl_right = 116
ctrl_home = 119
ctrl_end = 117
while user_input != enter:
char_g = getch()
user_input = ord(char_g)
prev_len = len(curr_chars) # track length for clearing stdout since length of curr_chars might change
if user_input == backspace:
if len(curr_chars) > 0 and cursor_pos <= len(curr_chars):
cursor_pos -= 1
curr_chars.pop(cursor_pos)
elif user_input == escape_code:
user_input = ord(getch())
if user_input == delete:
curr_chars.pop(cursor_pos)
elif user_input == left:
cursor_pos -= 1
elif user_input == right:
if cursor_pos < len(curr_chars):
cursor_pos += 1
elif user_input == home:
cursor_pos = 0
elif user_input == end:
cursor_pos = len(curr_chars)
elif user_input == ctrl_home:
curr_chars = curr_chars[cursor_pos:]
cursor_pos = 0
elif user_input == ctrl_end:
curr_chars = curr_chars[:cursor_pos]
cursor_pos = len(curr_chars)
elif user_input == ctrl_left:
try:
chars_left_of_cursor = "".join(curr_chars[:cursor_pos])
left_closest_space_char_index = [m.span()[0] for m in finditer(" \w", chars_left_of_cursor)][-1]
pos_diff = cursor_pos - left_closest_space_char_index - 1
cursor_pos -= pos_diff
except IndexError:
cursor_pos = 0
elif user_input == ctrl_right:
try:
chars_right_of_cursor = "".join(curr_chars[cursor_pos + 1:])
right_closest_space_char_index = [m.span()[0] for m in finditer(" \w", chars_right_of_cursor)][0]
cursor_pos += right_closest_space_char_index + 2
except IndexError:
cursor_pos = len(curr_chars) - 1
elif user_input != enter:
if cursor_pos > len(curr_chars) - 1:
curr_chars.append(char_g)
else:
curr_chars.insert(cursor_pos, char_g)
cursor_pos += 1
# clear entire line, write contents of curr_chars, reposition cursor
stdout.write("\r" + prev_len * " " + "\r")
stdout.write("".join(curr_chars))
pos_diff = len(curr_chars) - cursor_pos
stdout.write("\b" * pos_diff)
stdout.write("\r" + len(curr_chars) * " " + "\r")
stdout.write("".join(curr_chars) + "\n")
return "".join(curr_chars)
This is my first Stack overflow post and I hope to make a good impression.
I am working on a number guessing game in python to get my feet wet with unittest, but I am running into a silly conundrum.
The issue is that I want to create a unittest class that tests the following things
Does the pregenerated number match the guessed number
What does the program do if you enter in a letter
Do you see custom errors created when an error is occurring (in the try/except block)
My github project link is here -> https://github.com/robpedersendev/python-number-guessing-game
My main.py file is below
import random
import sys
def guessingGame(number, guess): # Answer and guess was placed here so as to allow the test to insert
# its own values into the game, but that is not working
while true:
try:
guess = input(
f"Number guesser.\t\t\n {name} choose a number between "
f"{start} and {end}. Enter guess? : ")
guess = int(guess)
if guess < number:
print("\n\nThat number is a tad low\n\n")
elif guess > number:
print("\n\nThat number is a tad high\n\n")
else:
print("\n\nCongrats, you chose the right number!\n\n")
break
except (TypeError, ValueError):
print("Sorry, numbers only please")
guess = str(f"\'{guess}\' Which is an invalid character")
continue
except (UnboundLocalError):
print("Sorry, numbers only please")
continue
finally:
print(f"{name}, your last successful guess was {guess}")
if __name__ == "__main__":
true = True
start = int(sys.argv[1])
end = int(sys.argv[2])
number = random.randrange(start, end) # Selects the winning number
name = input("\t\t\t\t\nHello stranger, whats your name? ")
guessingGame()
My test.py file looks like
import unittest
import main
class TestMain(unittest.TestCase):
def test_input(self):
true = True
number = 5
guess = 5
result = main.guessingGame(number, guess)
self.assertEqual(result)
if __name__ == "__main__":
unittest.main()
I keep getting the error
Traceback (most recent call last):
File "c:\Users\Robert\desktop\Side Projects\Udemy\Master python zero to Mastery\projects\python-number-guessing-game\test.py", line 10, in test_input
result = main.guessingGame(number, guess)
File "c:\Users\Robert\desktop\Side Projects\Udemy\Master python zero to Mastery\projects\python-number-guessing-game\main.py", line 6, in guessingGame
while true:
NameError: name 'true' is not defined
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (errors=1)
[Done] exited with code=1 in 0.375 seconds
Error message
I know I have much to do and much to learn, but I am hoping for some helpful guidance!
UPDATE:
Ok, I figured out the problem (kinda).
The issue is within my main.py file I need to have this
true = True
def guessingGame(number, guess, name='bob', start=1, end=20):
while true:
try:
# guess = input(
# f"Number guesser.\t\t\n {name} choose a number between "
# f"{start} and {end}. Enter guess? : ")
guess = int(guess)
if guess < number:
print("\n\nThat number is a tad low\n\n")
elif guess > number:
print("\n\nThat number is a tad high\n\n")
My test.py file
import unittest
import main
class TestMain(unittest.TestCase):
def test_input(self):
number = 5
guess = 5
start = 1
end = 20
name = "bob"
result = main.guessingGame(number, guess)
self.assertEqual(guess, number)
if __name__ == "__main__":
unittest.main()
I needed to predefine the values and comment out the first little block of code. Once I did that, my test passed!!
Any ideas, on how to get around this piece, or was this bad design on my part?
https://book.crawfordc.com/anatomy-of-a-modern-test-file
Here’s something I wrote a while back about writing unit tests with hypothesis and pytest.
For testing what goes wrong when you enter a letter you use the with pytest.raises pattern.
Using hypothesis to generate the random numbers will also work much better than your random number generation.
(You should just make the code while True: and not a variable. But you would need to return false if it failed. It would probably be better as a loop. )
Hello please forgive me if my question duplicate, I've searched previous questions and nothing seems to be quite the same. I'm working on a program that will scan a specific folder and search for specific file types to create a menu for a user to select. Once the user select the menu option the the corresponding file which is a power shell script. Currently My program does everything but run even a simple power shell script. I've attempted several configuration and it's not working. It would be great if someone can see what I may be doing wrong or provide me with some pointers. Code below.
##Text Menu Dynamic test
##version 1
## Created By Dragonshadow
## Code produce in Notpad++ For python v3.4.4
import os
import subprocess
import time
import pathlib
import logging
import fnmatch
import re
## Directory Enumerator
fileFolderLocationFilter = fnmatch.filter(os.listdir('C:\\Users\\myfolder\\Documents\\Automation_Scripts\\ENScripts\\'),"*.ps1")
selectedFile=""
## Menu defined setting veriables
def ENOC_menu():
files = fileFolderLocationFilter
counter = 1
print (20 * "=" , "Enoc Quick Menu" , 20 * "=")
enumFiles = list(enumerate(files))
for counter, value in enumFiles:
str = repr(counter) + ") " + repr(value);
print(str)
str = repr(counter+1) + ") Exit";
print(str)
print (57 * "_")
str = "Enter your choice [1 - " + repr((counter+1)) + "]:"
choice = int(input("Please Enter a Selection: "))
selectedFiles = enumFiles[choice]
return(selectedFiles[1])
if choice > counter :
choice = -1
elif choice != counter :
print("Please selecte a valid choice")
else:
selectedFiles = enumFiles[choice]
print(selectedFiles[1])
##selectedFiles = selectedFiles[1]
return choice
def you_sure():
opt = input("Are you sure Yes or No: ")
if opt=="Yes":
print("Continuing please wait this may take a moment...")
elif opt=="No":
print("returnig to Enoc Menu")
else: ##Stays in loop
print ("Please choose yes or no")
##count_down
def count_down ():
count_down = 10
while (count_down >= 0):
print(count_down)
count_down -= 1
if count_down == 0:
print("Task will continue")
break
##initiating loop
loop = True
while loop:
choice = ENOC_menu()
print ("\n" +"You selected "+ choice +"\n")
subprocess.call("C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\powershell.exe" + choice, shell=True)
##print ("---" +str(selectedFile))
You have probably already figured this out, but I the problem is in the subprocess.call() line. You are concatenating the powershell.exe path and the target file name together. See here:
>>> scriptToRun = "c:\\users\\Username\\Documents\\WindowsPowerShell\\classtestscript.ps1"
>>> powershellExe = "c:\\windows\\system32\\windowspowershell\\v1.0\\powershell.exe"
>>> print(powershellExe + scriptToRun)
c:\windows\system32\windowspowershell\v1.0\powershell.exec:\users\Username\Documents\WindowsPowerShell\classtestscript.ps1
Above, the two strings are stuck together without a space between them. Windows can't make sense of what you're trying to execute.
Put a space between the two two and subprocess.call() will understand what you're trying to do:
>>> print(powershellExe + ' ' + scriptToRun)
c:\windows\system32\windowspowershell\v1.0\powershell.exe c:\users\Username\Documents\WindowsPowerShell\classtestscript.ps1
I was wondering if it was possible to perform an action at any given point in a basic python script, so say when it is close. I have the following code to find prime numbers (Just for fun)
number = 1
primelist = []
nonprime = []
while number < 1000:
number += 1
for i in range(number):
if i != 1 and i != number and i !=0:
if number%i == 0:
nonprime.append(number)
else:
primelist.append(number)
nonprimes = open("nonprimes.txt", "w")
for nonprime in set(primelist) & set(nonprime):
nonprimes.write(str(nonprime) + ", ")
nonprimes.close()
So basically i wanted to run the last part as the script is stopped. If this isn't possible is there a way where say i press "space" while the program is running and then it saves the list?
Cheers in advance :)
EDIT:
I've modified the code to include the atexit module as suggested, but it doesn't appear to be working. Here it is:
import time, atexit
class primes():
def __init__(self):
self.work(1)
def work(self, number):
number = 1
self.primelist = []
self.nonprime = []
while number < 20:
time.sleep(0.1)
print "Done"
number += 1
for i in range(number):
if i != 1 and i != number and i !=0:
if number%i == 0:
self.nonprime.append(number)
else:
self.primelist.append(number)
nonprimes = open("nonprimes.txt", "w")
for nonprime in set(self.primelist) & set(self.nonprime):
nonprimes.write(str(nonprime) + ", ")
nonprimes.close()
def exiting(self, primelist, nonprimelist):
primelist = self.primelist
nonprimelist = self.nonprime
nonprimes = open("nonprimes.txt", "w")
for nonprime in set(self.primelist) & set(self.nonprime):
nonprimes.write(str(nonprime) + ", ")
nonprimes.close()
atexit.register(exiting)
if __name__ == "__main__":
primes()
While I'm pretty certain the file object does cleanup and flushes the stuff to file when it is reclaimed. The best way to go about this is to use a with statement.
with open("nonprimes.txt", "w") as nonprimes:
for nonprime in set(primelist) & set(nonprime):
nonprimes.write(str(nonprime) + ", ")
The boiler plate code of closing the file and such is performed automatically when the statement ends.
Python has an atexit module that allows you to register code you want executed when a script exits:
import atexit, sys
def doSomethingAtExit():
print "Doing something on exit"
atexit.register(doSomethingAtExit)
if __name__ == "__main__":
sys.exit(1)
print "This won't get called"