24 game using Python3 - python-3.x

24 is a mental arithmetic game, first played using poker cards. Given four integers, the objective is to produce the number 24 using the standard arithmetic operators +, −, ∗ and /, while consuming all four numbers in the process.
For example, given the numbers { 2, 3, 5, 6 }, one could do . . .
2 * 3 = 6 , 5 * 6 = 30 , 30 - 6 = 24 and so on
Note: The given numbers can be used in any order to produce 24.
Write a program that takes in four integers, and determines whether it is possible to reach 24 from those numbers. You can assume the number 0 will not form part of the input.
I am not sure how to let the function run my 4 inputs
import itertools
ints = input('Enter 4 integers: ').split()
n1=int(ints[0])
n2=int(ints[1])
n3=int(ints[2])
n4=int(ints[4])
def with_brackets(lst, ops_lst):
for op in ops_lst: #calculate when no brackets
expr1 = '('+lst[0]+op[0]+lst[1]+')'+op[1]+lst[2]+op[2]+lst[3]
expr2 = '('+lst[0]+op[0]+lst[1]+op[1]+lst[2]+')'+op[2]+lst[3]
expr3 = lst[0]+op[0]+'('+lst[1]+op[1]+lst[2]+')'+op[2]+lst[3]
expr4 = '('+lst[0]+op[0]+lst[1]+')'+op[1]+'('+lst[2]+op[2]+lst[3]+')'
for expr in [expr1, expr2, expr3, expr4]:
try:
t=eval(expr)
except: #except zerodivision error
pass
if abs(t-24) < 0.001:
return expr
return 0
#return 4 numbers to calculate 24
def hasMethod(numbers, ops_lst):
for lst in itertools.permutations(numbers):
lst = list(map(lambda x:str(x), lst))
#without brackets
for op in ops_lst:
expr = lst[0]+op[0]+lst[1]+op[1]+lst[2]+op[2]+lst[3]
if abs(eval(expr)-24) < 0.001:
return expr
#with brackets
expr = with_brackets(lst, ops_lst)
if expr != 0:
return expr
return 0
#method of return 4 numbers to calculate 24,no way return"No Method"
def cal_24(numbers):
ops = ['+','-','*','/']
ops_lst = [[i,j,k] for i in ops for j in ops for k in ops]
expr = hasMethod(numbers, ops_lst)
if expr != 0:
return expr
else:
return 'No method!'
#ways to calculate 24 at all situaions
def main():
numbers_lst = [[i,j,k,l] for i in range(1,14) for j in range(1,14)\
for k in range(1,14) for l in range(1,14)]
for numbers in numbers_lst:
a = list(map(lambda x: str(x), numbers))
methodInfo = "[%s,%s,%s,%s]: %s\n"%(a[0],a[1],a[2],a[3],cal_24(numbers))
print(methodInfo)
main()
Expected results:
Example 1:
Enter 4 integers: 2 3 5 6
Yes! 24 is reachable from { 2, 3, 5, 6 }
Example 2:
Enter 4 integers: 1 1 1 1
Noooo :( 24 is unreachable from { 1, 1, 1, 1 }
Example 3:
Enter 4 integers: hello
Input must consist of 4 integers

This question is very interesting.
from __future__ import division, print_function
import random, ast, re
import sys
if sys.version_info[0] < 3: input = raw_input
def choose4():
'four random digits >0 as characters'
return [str(random.randint(1,9)) for i in range(4)]
def welcome(digits):
print (__doc__)
print ("Your four digits: " + ' '.join(digits))
def check(answer, digits):
allowed = set('() +-*/\t'+''.join(digits))
ok = all(ch in allowed for ch in answer) and \
all(digits.count(dig) == answer.count(dig) for dig in set(digits)) \
and not re.search('\d\d', answer)
if ok:
try:
ast.parse(answer)
except:
ok = False
return ok
def main():
digits = choose4()
welcome(digits)
trial = 0
answer = ''
chk = ans = False
while not (chk and ans == 24):
trial +=1
answer = input("Expression %i: " % trial)
chk = check(answer, digits)
if answer.lower() == 'q':
break
if answer == '!':
digits = choose4()
print ("New digits:", ' '.join(digits))
continue
if not chk:
print ("The input '%s' was wonky!" % answer)
else:
ans = eval(answer)
print (" = ", ans)
if ans == 24:
print ("Thats right!")
print ("Thank you and goodbye")
if __name__ == '__main__': main()

Related

How to find the first odd digit in an integer recursively

I am new to python and am trying to get more comfortable with recursion. I am trying to find the first odd digit of a integer recursively. If there are no odd digits found return -1. Whenever I run this code I always get 35 instead of just 5.
This is what I have tried
def first_odd(n):
if n == 0:
return 0
elif n % 2 == 1:
return first_odd(n//10) * 10 + n%10
else:
return first_odd(n//10)
print(first_odd(2345))
If I understand your recent comment to Tarik correctly, it sounds like you want a function that will return the first odd digit scanning an integer right to left and if no odd digits are found then return -1. For example, in your original post you stated that with the integer 2345 you expected the value of 3, but based on your comment it sounds like 5 would be the correct answer scanning right to left, right? If so, then the following code should meet that description.
from random import randint
def find_rightmost_odd_digit(number):
while number:
rightmost_digit = number % 10
if rightmost_digit % 2:
return rightmost_digit
number = number // 10
return -1
for _ in range(10):
number = randint(0, 1000)
print(f"{number:>10}{find_rightmost_odd_digit(number):>4}")
Output:
387 7
88 -1
639 9
196 9
986 9
232 3
82 -1
907 7
948 9
214 1
You were basically on the correct track but just included an extra recursion you didn't need. Consider:
def first_odd(n):
if n == 0:
return -1
if n % 2 == 1: # number is odd, return last digit
return n % 10
return first_odd(n // 10)
If this works as intended, then I might implement it as follows to combine a couple of the divisions:
def first_odd(n):
if n == 0:
return -1
quotient, remainder = divmod(n, 10)
if remainder % 2 == 1: # remainder is odd, return it
return remainder
return first_odd(quotient)
Is there also a way to find the first odd digit from left to right
using 1 parameter?
from math import log10
def first_left_odd(n):
if n == 0:
return -1
power = 10 ** int(log10(n))
digit = n // power
if digit % 2 == 1:
return digit
return first_left_odd(n - digit * power)
Or if using the math library and/or log10() is an issue, then:
def first_left_odd(n):
if n < 10:
return n if n % 2 == 1 else -1
result = first_left_odd(n // 10)
if result != -1:
return result
return first_left_odd(n % 10)
Building complex programs is a matter of combining several simple programs. For this problem I would write a program that breaks a number into digits, and one that checks if any particular number is_odd -
def first_odd(n):
for d in digits(n):
if is_odd(d):
return d
return None
We can write digits and is_odd easily -
def is_odd(n):
return n & 1
def digits(n):
if n < 0:
yield from digits(n * -1)
elif n < 10:
yield n
else:
yield from digits(n // 10)
yield n % 10
print(first_odd(2345)) # 3
print(first_odd(6804721)) # 7
print(first_odd(2468)) # 9
print(first_odd(-465321)) # 5
This might do it:
def first_odd(n, digit):
if n == 0:
return None
elif n % 2 == 1:
return digit
else:
return first_odd(n//10, digit+1)
first_odd(2345, 0)
If you want the first digit to be 1, pass 1 instead of 0
Ok, this is for left to right:
def first_odd(n, digit):
if n == 0:
return None
pos = first_odd(n//10, digit+1)
if pos is None and n % 2 == 1:
return digit
else:
return pos

Why is my simple code taking so much time to execute when i give in large numbers as input?

I have written a simple code to print the largest prime factor of a given number from Project Euler. It works just fine for numbers like 24, but there is no response from the python shell for large numbers!
a=600851475143
b=[]
for i in range(2,600851475143):
if a%i==0:
if i==2:
b.append(i)
continue
for j in range(2,i+1):
if j==i:
b.append(i)
if i%j==0:
break
print(max(b))
print(b)
You can use an algorithm like this to get large factors of prime numbers:
import math
def LLL(N):
p = 1<<N.bit_length()-1
if N == 2:
return 2
if N == 3:
return 3
s = 4
M = pow(p, 2) - 1
for x in range (1, 100000):
s = (((s * N ) - 2 )) % M
xx = [math.gcd(s, N)] + [math.gcd(s*p+x,N) for x in range(7)] + [math.gcd(s*p-x,N) for x in range(1,7)]
try:
prime = min(list(filter(lambda x: x not in set([1]),xx)))
except:
prime = 1
if prime == 1:
continue
else:
break
return N/prime

Infix to Postfix using a stack w/Regex

I'm trying to figure out a homework assignment and I've run into a very specific weird problem. Basically I'm using regex to pull all of the operators and operands out one at a time in order of operations, and then pop them off a stack while printing them in the correct postfix notation. It works in most cases, however when running the unittest it fails test_infix14, test_infix_bad_expression, and test bad postfix. I can tell that it's something to do with the way + and - is coming out of the expression (I think) but I have no idea what's making it do it this way. Any help is appreciated. I thought I had this one good and done on Friday but this one little issue has occupied 2 whole days :P
''' Main Driver Code '''
import re
import stack
def eval_postfix(postfix):
''' Postfix '''
stac = stack.Stack()
tokens = re.findall(r'\d+|\+|\-|\*|\/', postfix)
if len(tokens) == 0:
raise ValueError
if len(tokens) < 2:
return float(tokens[0])
for toke in tokens:
if toke.isnumeric():
stac.push(float(toke))
else: # t is an operator
op1 = stac.pop() #operand 1
op2 = stac.pop() #operand 2
if toke == '+':
result = op2 + op1
elif toke == '-':
result = op2 - op1
elif toke == '*':
result = op2 * op1
elif toke == '/':
result = op2 / op1
stac.push(result)
return float(stac.pop())
def precedence(top, inputSymbol): # check if top has >= precedence than inputSymbol
''' Helper precedence function '''
if len(re.findall(r'\(|\)|\-|\+|\*|\/', top)) > 0: # if top of stack is an operator
prec = ['(', '-', '+', '*', '/', ')'] # ascending precedence
topPrec = prec.index(top) #e.g.: top == '+', then topPrec == 1
symbol_input = prec.index(inputSymbol)
#e.g.: inputSymbol == '/', then symbol_input == 4
return topPrec >= symbol_input #e.g.: 1 >= 4: false
return False
def in2post(infix):
result = ""
if infix == [None]:
raise ValueError
tokens = re.findall(r'\d+|\(|\)|\+|\-|\*|\/', infix)
stac = stack.Stack()
for t in tokens:
if t == '(':
stac.push(t)
elif t.isnumeric():
result += t + ' '
elif len(re.findall(r'\+|\-|\*|\/', t)) > 0:
while stac.size() > 0 and precedence(stac.peek(), t): #and s.peek() != '('
result += stac.pop() + ' '
stac.push(t)
else:
result += stac.pop() + ' '
while stac.peek() != '(':
result += stac.pop() + ' '
stac.pop()
while stac.size() > 0:
if stac.peek() != '(':
result += stac.pop() + ' '
return result
def main():
''' Main Function '''
with open("data.txt") as file:
for line in file.readlines():
print("infix: %s" % line, end='')
postfix = in2post(line)
print("postfix: %s" % postfix)
answer = eval_postfix(postfix)
print("answer: %s" % answer)
print()
if __name__ == '__main__':
main()
''' stack class '''
class Stack:
''' see above doc string '''
def __init__(self):
''' constructor '''
self.stack_array = []
def push(self, item):
''' add to the stack '''
self.stack_array.append(item)
def pop(self):
''' remove from the array '''
#try:
# return self.stack_array.pop()
#except IndexError:
# print(self.stack_array)
if len(self.stack_array) == 0:
raise IndexError
return self.stack_array.pop()
def peek(self):
''' See top item of array '''
#if self.stack_array == [')']:
# raise SyntaxError
if len(self.stack_array) == 0:
raise IndexError
return self.stack_array[-1]
def size(self):
''' get total size of array '''
return len(self.stack_array)
def clear(self):
''' clear whole array '''
self.stack_array = []
import unittest
from stack import Stack
from main import eval_postfix as epf
from main import in2post as i2p
from main import main as mn
import io
import sys
class TestEvaluation(unittest.TestCase):
def test_bad_postfix(self):
self.assertRaises(SyntaxError, epf, " 7 9 * 7 + 5 6 * - 3 + 4 -+")
self.assertRaises(ValueError, epf, [None])
class TestIn2Postfix(unittest.TestCase):
def test_infix_14(self):
postfix = i2p("7*9+7-5*6+3-4")
self.assertEqual(postfix.replace(" ", ""), "7 9 * 7 + 5 6 * - 3 + 4 -".replace(" ", ""))
def test_infix_bad_expression(self):
self.assertRaises(SyntaxError, i2p, "(8+3)*(5-6))")
class TestMainOutput(unittest.TestCase):
def test_main_output(self):
self.maxDiff = None
captured_output = io.StringIO()
sys.stdout = captured_output
mn()
sys.stdout = sys.__stdout__
data = "".join(captured_output.getvalue().split())
print(sys.stdout)
data1 = "infix: 4postfix: 4answer: 4.0infix: 5 +7postfix: 5 7 +answer: 12.0infix: 7*5postfix: 7 5 *answer: 35.0infix: (5-3)postfix: 5 3 -answer: 2.0infix: 5/5postfix: 5 5 /answer: 1.0infix: 8*5+3postfix: 8 5 * 3 +answer: 43.0infix: 8*(5+3)postfix: 8 5 3 + *answer: 64.0infix: 8+3*5-7postfix: 8 3 5 * + 7 -answer: 16.0infix: (8+3)*(5-6)postfix: 8 3 + 5 6 - *answer: -11.0infix: ((8+3)*(2-7))postfix: 8 3 + 2 7 - *answer: -55.0infix: ((8+3)*2)-7postfix: 8 3 + 2 * 7 -answer: 15.0infix: (8*5)+((3-2)-7*3)postfix: 8 5 * 3 2 - 7 3 * - +answer: 20.0infix: ((8*5+3)-7)-(5*3)postfix: 8 5 * 3 + 7 - 5 3 * -answer: 21.0infix: 7*9+7-5*6+3-4postfix: 7 9 * 7 + 5 6 * - 3 + 4 -answer: 39.0".replace(" ","")
self.assertEqual(data, data1)
The problem is in your precedence function. The rules for the Shunting yard algorithm say:
if the token is an operator, then:
while ((there is a function at the top of the operator stack)
or (there is an operator at the top of the operator stack with greater precedence)
or (the operator at the top of the operator stack has equal precedence and the token is left associative))
and (the operator at the top of the operator stack is not a left parenthesis):
pop operators from the operator stack onto the output queue.
push it onto the operator stack.
Addition and subtraction (+ and -) have equal precedence, and multiplication and division (* and /) have equal precedence. But your precedence function gives + higher precedence than -, and * higher than /. That will give the wrong output.
For example, if you're given the infix expression 7-3+4, then after parsing the 3, your output is 7 3, and the stack contains -. You parse the + and you see that + has higher precedence than -, so you push it onto the operator stack. Then you parse 4 and end up with output of 7 3 4. Finally, you start popping the stack, ending up with 7 3 4 + 1. Which will evaluate as 7 - (3 + 4).
You have to change your precedence function so that - and + have the same precedence. And * and / have the same precedence.

Select a number randomly with probability proportional to its magnitude from the given array of n elements

Ex 1: A = [0 5 27 6 13 28 100 45 10 79]
let f(x) denote the number of times x getting selected in 100 experiments.
f(100) > f(79) > f(45) > f(28) > f(27) > f(13) > f(10) > f(6) > f(5) > f(0)
My code:
def pick_a_number_from_list(A,l):
Sum = 0
#l = len(A)
for i in range(l):
Sum+=A[i]
A_dash = []
for i in range(l):
b=A[i]/Sum
A_dash.append(b)
#print(A_dash)
series = pd.Series(A_dash)
cumsum = series.cumsum(skipna=False)
#print(cumsum[9])
sample_value = uniform(0.0,1.0)
r = sample_value
print(r)
#for i in range(l):
if r<cumsum[1]:
return 1
elif r>cumsum[1] and r <cumsum[2]:
return 2
elif r<cumsum[3]:
return 3
elif r<cumsum[4]:
return 4
elif r<cumsum[5]:
return 5
elif r<cumsum[6]:
return 6
elif r<cumsum[7]:
return 7
elif r<cumsum[8]:
return 8
elif r<cumsum[9]:
return 9
def sampling_based_on_magnitued():
A = [0,5,27,6,13,28,100,45,10,79]
n = len(A)
#for i in range(1,10):
num = pick_a_number_from_list(A,n)
print(A[num])
sampling_based_on_magnitued()
In mu code i am using multiple if else statement and because it is hardcoded
i can make by o/p right till 10 element in the list.
I want to make my code dynamic for any value in the list.
Here in my code i have restricted it to n=10
Pls tell me how can i right generic code which can replace all if - elseif statement with for loop
sum1=0;
for i in A:
sum1+=i;
x=0
list1=[]
for i in A:
list1.append(x+i/sum1)
x=x+i/sum1;
#list1 contsins cumulative sum
bit=uniform(0,1)
for i in range (0,len(list1)):
if bit<list1[i]:
return A[i]
you may use this
you can use random.choices
A = [0,5, 27, 6, 13, 28, 100, 45, 10, 79]
let no of random values want to pick it be 100 s0 k=100
w = [0.0, 0.01597444089456869, 0.08626198083067092, 0.019169329073482427, 0.04153354632587859, 0.08945686900958466, 0.3194888178913738, 0.14376996805111822, 0.03194888178913738, 0.2523961661341853]
weights is calculsted by using A[i]/(total sum of all the values of A)
x = random.choices(A,w,k=100)
print(x)
it displays the values from list A according to there weights
Some changes in Bitan Guha Roy's code to return just one value
import numpy as np
sum1=0;
for i in A:
sum1+=i;
x=0
list1=[]
for i in A:
list1.append(x+i/sum1)
x=x+i/sum1;
# list1 contains cumulative sum
bit=np.random.uniform(0.0,1.0,1)
for i in range (0,len(list1)):
if bit>=list1[i] and bit<list1[i+1]:
print(A[i+1]) # or return if under a function
import random
lst=[0, 5 ,27, 6, 13, 28, 100, 45, 10,79]
def pick_a_number_from_list(A):
weights1=[]
for i in A:
weights1.append(i/sum(lst))
selected_random_number = random.choices(A,weights=weights1,k=1)
return selected_random_number
def sampling_based_on_magnitued():
for i in range(1,100):
number=pick_a_number_from_list(lst)
print(number)
sampling_based_on_magnitued()
# used random.choices which gives option to choose random number according respective weights. Please suggest any modification if you've any

Print prime numbers in a range of given numbers

I'm trying to print all primes into a range of given numbers (low and max, given numbers included).
For example:
num1=10, num2=20
>>> 11, 13, 17, 19
My code fails in some occasions and I can't understand why:
num1 = int(input('First number is: '))
num2 = int(input('Second number is: '))
if num2 <= num1:
num1,num2 = num2,num1
for i in range(num1, num2+1):
for p in range(2,int(num2**0.5)+1):
if i%p == 0:
break
else:
print(i,' ',end = '')
print('\n')
Results:
1 to 7 >>> 1 3 5 7 (omits 2)
1 to 30 >>> 1 7 11 13 17 19 23 29 (omits 2,3,5)
1 to 60 >>> 1 7 11 13 17 19 23 29 (omits 2,3,5,7)
0 to 0 >>> 0 (prints 0 -> not a prime number)
0 to 7 >>> 1 3 5 7 (omits 2)
How can I correct this? Thanks a bunch!
ps. number 1 is not a prime too.
The mistake in your code was not having an i in the second part of the inner for loop range as opposed to num2
num1 = int(input('First number is: '))
num2 = int(input('Second number is: '))
if num2 > num1:
num1, num2 = num2, num1
for i in range(num1, num2+1):
if i == 0 or i == 1: continue
for p in range(2,int(i**0.5)+1): # the second part should be int(i**0.5) + 1, not int(num2**0.5)+1
if i%p == 0:
break
else:
print(i,' ',end = '')
Also rather than having two branches for num1 < num2 and the other way around, you can do something like below. Further in terms of code design, it would be better to decompose this slightly into an is_prime method. That way, if you ever want to write a quicker primality tester, you could easily edit the helper function as opposed to messing with the main code.
def is_prime(num):
if i == 1: return False
for p in range(2,int(num**0.5)+1):
if num % p == 0:
return False
return True
inp1 = int(input('First number is: '))
inp2 = int(input('Second number is: '))
num1 = min(inp1, inp2)
num2 = max(inp1, inp2)
for i in range(num1, num2+1):
if is_prime(i):
print(i,' ',end = '')
print('\n')
You didn't consider the division of the number by the number itself into consideration.
i.e. When range was 1 to 30, sqrt(30)+1 = 5+1 = 6, all nos below six had a case where they were divided by the number itself as 2%2,3%3 ... i%i.
Workaround would be to change the range of inner for loop as :
for i in range(num1, num2+1):
for p in range(2,int(i**0.5)+1): #Change num2 to i to avoid i%i
if i%p == 0:
break
else:
print(i,' ',end = '')
It is better to abstract the code like the one done by gowrath to avoid mistakes.

Resources