Random Simulation of 20 Die Throws - python

Trying to simulate 20 dice throws randomly, the code needs to enclose with parenthesis a value that is the same, the parenthesis appear, but I am missing something on my formula, any advise can greatly help, eg:
1 ( 4 1 ) 2 3 6 1 4 3 2 6 6 6 5 6 2 1 3 5 3 # incorrect
1 4 1 2 3 6 1 4 3 2 ( 6 6 6 ) 5 6 2 1 3 5 3 # this is a correct example
def main():
exampleList = [ ]
for i in range(20):
exampleList.append(randint(1, 6))
print(exampleList)
print(list(range(0,20)))
max_count = 0
run_count = 0
matched = False #inRun = False
# find max run
for rollValue in exampleList:
#print(rollValue)
if run_count == 19:
print()
else:
print("-------")
print("Roll Value %s" % exampleList[run_count])
print("Position %s" % run_count)
print("Next Roll value %s" % exampleList[run_count + 1])
if exampleList[run_count] == exampleList[run_count + 1]:
matched = True
print("------->>>matched")
else:
matched = False#inRun = False
run_count += 1
if rollValue < 19:
if exampleList[rollValue] == exampleList[rollValue + 1]:
run_count += 1
if matched == False:
matched == True
run_count = rollValue
else:
matched = False
if run_count > max_count:
run_count = 1
# print sequence
for rollValue in range(20):
if rollValue == run_count:
print("(", exampleList[rollValue], end = " ")
elif rollValue == run_count + max_count + 1:
print(exampleList[rollValue], ")", end = " ")
else:
print(exampleList[rollValue], end = " ")
main()

Here is a solution using regex. This creates a string out of the dice rolls, then finds repeating digits and uses re.sub to add parenthesis.
import re
import random
rolls = ''.join(map(str, [random.choice(range(1, 7)) for _ in range(20)]))
rolls = ' '.join(re.sub(r'(\d)(\1+)', r'(\1\2)', rolls))
print(rolls)
A couple sample runs:
4 1 4 3 4 6 5 2 3 ( 5 5 ) 1 6 4 3 5 2 5 ( 4 4 )
2 ( 1 1 ) 4 1 ( 5 5 ) ( 3 3 ) 6 2 ( 1 1 ) 5 1 4 3 4 ( 5 5 )
Regex explanation:
( // start of matching group 1
\d // matches a single digit
) // end of matching group 1
( // start of matching group 2
\1+ // matches group 1, 1 or more times
) // end of matching group 2

This adds the parenthesis as part of the list:
#!/usr/bin/python
import sys
from random import randint
# add parenthesis as part of the list
def main():
exampleList = [ ]
previous = -1
opened = False
for i in range(20):
roll = randint(1, 6)
if roll == previous:
if not opened:
exampleList.insert(-1, '(')
opened = True
else:
if opened:
exampleList.append(')')
opened = False
exampleList.append(roll)
previous = roll
if opened:
exampleList.append(')')
for item in exampleList:
sys.stdout.write('{0} '.format(item))
sys.stdout.write('\n')
if __name__ == '__main__':
main()
Examples:
( 2 2 ) 4 5 1 2 1 ( 6 6 ) 1 6 1 4 1 ( 6 6 ) 1 6 2 4
2 ( 6 6 ) ( 1 1 ) 3 2 1 ( 4 4 ) 1 2 5 4 1 5 3 ( 5 5 5 )

There are a number of issues with your code, so it was just quicker to rewrite the whole thing.
def main():
example_list = []
for _ in range(20):
example_list.append(random.randint(1, 6))
inside = False
for index in range(len(example_list)):
try:
if inside:
if example_list[index] != example_list[index + 1]:
print("%d )" % example_list[index], end=" ")
inside = False
else:
print(example_list[index], end=" ")
else:
if example_list[index] == example_list[index + 1]:
print("( %d" % example_list[index], end=" ")
inside = True
else:
print(example_list[index], end=" ")
except IndexError:
print("%d" % example_list[index], end=" ")
if inside:
print(")")
else:
print()
As you can see I keep track of whether I'm inside a parenthesis by using a variable. I look to the next number to guess if I should add a closing parenthesis.
The last case is handled by a try-except.
You could also handle each number by looking forward and backward but that'd require you to add some extra condition for the try-except part so this was just

There are various ways to do this, but this is the most similar to what you were doing already. Basically just iterate over the index of your list of rolls. Each number we examine it to see if it is the same as the one before, if yes, then we increment the count and move on. If not then we add however many of that number were in the count to the output. If there was one, we write it out by itself, if more, in parenthesis.
exampleList = [randint(1, 6) for i in range(20)]
# the current number that could be a potential sequence
current = exampleList[0]
# count for the number of occurences in a sequence (often 1)
count = 1
# The string to outpu
output = ''
# Iterate over the rolls, ignoring the first one
for i in range(1, len(exampleList)):
if exampleList[i] == current:
count += 1
else:
if count > 1:
output += ('(' + count * str(current) + ')')
else:
output += str(current)
current = exampleList[i]
count = 1
# Handle final addition
if count > 1:
output += ('(' + count * str(current) + ')')
else:
output += str(current)
print(output)
Output:
64(66)15253(66)2143454(22)

The logical error is that you're confusing "the index where the run starts" with "the length of the (last) run".
You need a variable like max_run_start_index.
Look at the code:
if rollValue == run_count:
print("(", exampleList[rollValue], end = " ")
Read it back to yourself 'if the index of the next output is equal to the length of the last run, output open bracket before it'.
So if the length of the last run is 3 the longest run starts at index 3?
Surely not...
I'm not a Python coder, so you'll need to fix it yourself...

Related

Looping Based on 2 Value Python

i have 2 variable
ex :
compt = 9
first = 3
second = 2
then i want to looping based on compnt length and then change status on or off based on variable first and second
Output that i want :
On
On
On
Off
Off
On
On
On
Off
my current code is:
x,y=0,0
for i in range(0,compt):
if x != first:
print("On")
x+=1
elif x == first and y != second:
print("Off")
but the output from code above is
On
On
On
Off
Off
On
On
On
On
can someone help me to solve my problem , thank you
compt = 9
first = 3
second = 2
for i in range(compt):
max_val = first + second
if i % max_val < first:
print("on")
else:
print("off")
Output:
on
on
on
off
off
on
on
on
off
from itertools import cycle, islice
total = 9
first = 3
second = 2
sequence = ["On" for _ in range(first)] + ["Off" for _ in range(second)]
print(sequence)
result = islice(cycle(sequence), 0, total)
for state in result:
print(state)
output :
['On', 'On', 'On', 'Off', 'Off']
On
On
On
Off
Off
On
On
On
Off
Another variation with itertools:
from itertools import cycle, repeat, chain
compt = 9
first = 3
second = 2
on = repeat("On", first) # ["On", "On", ..]
off = repeat("Off", second) # ["Off", "Off", ..]
for status in cycle(chain(on, off)): # combine on and off and repeat
print(status)
# break when compt is exhausted
compt -= 1
if compt <= 0:
break
You can use %. We have a total first + second possibility. If our i is less than first it means that we are looking for on and if it's more than first we want to print off:
compt = 9
first = 3
second = 2
for i in range(compt):
if i % (first + second) < first:
print("ON")
else:
print("OFF")
try it...
compt = 9
first = 3
second = 2
i=0
while i < compt:
for k in range(0,first):
i += 1
print('on')
if i >= compt:
break
for j in range(0,second):
i += 1
print('off')
if i >= compt:
break

Count number's digits following by line

I have the number 444333113333 and I want to count every different digit in this number.
4 is 3 times
3 is 3 times
1 is 2 times
3 is 4 times
What I am trying to do is make a script that translates phone keypad taps to letters
like in this photo https://www.dcode.fr/tools/phone-keypad/images/keypad.png
if I press 3 times number 2, then the letter is 'C'
I want to make a script with it in python,but I cannot...
Using regex
import re
pattern = r"(\d)\1*"
text = '444333113333'
matcher = re.compile(pattern)
tokens = [match.group() for match in matcher.finditer(text)] #['444', '333', '11', '3333']
for token in tokens:
print(token[0]+' is '+str(len(token))+' times')
Output
4 is 3 times
3 is 3 times
1 is 2 times
3 is 4 times
You can use itertools.groupby
num = 444333113333
numstr = str(num)
import itertools
for c, cgroup in itertools.groupby(numstr):
print(f"{c} count = {len(list(cgroup))}")
Output:
4 count = 3
3 count = 3
1 count = 2
3 count = 4
Will this do the trick?
the function returns a 2d list with each number and the amount it found. Then you can cycle through the list and to get each all of the values
def count_digits(num):
#making sure num is a string
#adding an extra space so that the code below doesn't skip the last digit
#there is a better way of doing it but I can't seem to figure out it on spot
#essemtially it ignores the last set of char so I am just adding a space
#which will be ignored
num = str(num) + " "
quantity = []
prev_char = num[0]
count = 0
for i in num:
if i != prev_char:
quantity.append([prev_char,count])
count = 1
prev_char = i
elif i.rfind(i) == ([len(num)-1]):
quantity.append([prev_char,count])
count = 1
prev_char = i
else:
count = count + 1
return quantity
num = 444333113333
quantity = count_digits(num)
for i in quantity:
print(str(i[0]) + " is " + str(i[1]) + " times" )
Output:
4 is 3 times
3 is 3 times
1 is 2 times
3 is 4 times

sequence of repeated values in a list

I have problems with a program, I hope someone can help me to fix this. Basically I have a random generated list with 20 values, and I want to place between brackets the values that are repeated (for example if the list is [1,2,2,4,5] it should display 1 ( 2 2 ) 4 5 )
Now here's my code that works only if there is no repeated value in the end, because the list index goes out of range. How can I fix this?
from random import randint
lanci = []
for i in range(20):
x = randint(1,6)
lanci.append(x)
print(lanci)
i=0
while i < len(lanci)-1):
if lanci[i] == lanci[i+1]:
print("(",end=" ")
print(lanci[i],end=" ")
while lanci[i]==lanci[i+1]:
i = i + 1
print(lanci[i],end=" ")
print(")",end=" ")
else:
print(lanci[i],end=" ")
i = i + 1
Alternatively to your more manual approach, you could use itertools.groupby to group equal values in the list and then enclose those in parens:
>>> import random, itertools
>>> lst = [random.randint(1, 5) for _ in range(20)]
>>> tmp = [list(map(str, g)) for k, g in itertools.groupby(lst)]
>>> ' '.join(g[0] if len(g) == 1 else "(" + " ".join(g) + ")" for g in tmp)
'5 4 1 2 1 4 (5 5) 4 5 1 5 4 3 (5 5) 3 (5 5 5)'
Not the pretiest but will do it:
from random import randint
from itertools import groupby
lanci = [randint(1,6) for _ in range(20)]
result = [tuple(v) for _, v in groupby(lanci)]
print(*[i[0] if len(i) == 1 else '('+' '.join(map(str, i))+')' for i in result], sep=' ')
#(2 2) 3 5 3 1 5 4 6 2 1 4 6 4 (5 5) 3 6 3 4
Just check for "last element" before your inner while loop.
from random import randint
lanci = []
for i in range(20):
x = randint(1,6)
lanci.append(x)
print(lanci)
i=0
while i < len(lanci)-1):
if lanci[i] == lanci[i+1]:
print("(",end=" ")
print(lanci[i],end=" ")
while (i+1 < len(lanci)) and (lanci[i]==lanci[i+1]):
i = i + 1
print(lanci[i],end=" ")
print(")",end=" ")
else:
print(lanci[i],end=" ")
i = i + 1
convert the list of number to a string then you can use this function.
split it if you need the list back again.
def add_brackets(string):
_character, _index = None, 0
_return_string = ''
for i, c in enumerate(string+ ' '):
if _character is None or _character != c :
if len(string[_index:i])>1:
_return_string+='(' + string[_index: i] + ')'
else:
_return_string+=string[_index: i]
_character, _index = c, i
return _return_string
This is another option using just basic list:
def group_consecutives(lst):
res, sub, memo = [None], [], None
lst.append(memo)
for x in lst:
if memo == x:
sub.append(memo)
if res[-1] != sub: res.append(sub)
else:
sub.append(memo)
if memo and not len(sub) > 1: res.append(memo)
memo, sub = x, []
return res[1:]
print(group_consecutives(lanci))

Formatting and transforming data in Python

I am trying to reformat somewhat inconsistent values (OCR) to a standard form based on a set of rules. These values come over typically as a fraction i.e. 4 3/4 but the values are sometimes polluted with other random characters i.e. 4 .3/4. The values can also be non fractional floats (4.75). The goal is to grab the values and produce the number; input = 'T 3/' output = 3. The values will never exceed 11.
I'm sure there's a better way to do this, but this is what I have so far, and it works on most but it doesn't catch everything. Any help to help handle exceptions like 'T 3/' would be appreciated.
a = ' Y 3/'
def get_num(t):
return str(''.join(ele for ele in t if ele.isdigit()))
t = get_num(a)
y = int(t)
z = a.split('.')[0]
print len(t)
if '/' in a:
if int(str(y)[:1]) == 1 and int(str(t)[1]) != 1 and len(t) == 4 and t <1199:
print '{}{} {}/{}'.format(*t)
if int(str(y)[:1]) == 1 and int(str(t)[1]) != 1 and len(t) == 4 and t >1199:
print '{} {}/{}'.format(*t[1:])
if int(str(y)[:1]) != 1 and int(str(t)[1]) != 1 and len(t) == 3:
print '{} {}/{}'.format(*t)
if int(str(y)[:1]) != 1 and int(str(t)[1]) == 1 and len(t) == 3:
print '{} {}/{}'.format(*t)
elif '.' in a and '/' not in a:
if int(z) == 1 and len(z) == 1:
print a.replace(' ','')
if int(z) > 11 and len(z) > 1 and int(t[:1]) == 1:
print a.replace(' ','')[1:]
if int(z) != 1 and len(z) <= 2:
print a.replace(' ','')
elif '.' not in a and '/' not in a:
if int(str(y)[:1]) == 1 and int(str(t)[1]) != 1 and len(t) == 4 and t <1199:
print '{}{} {}/{}'.format(*t)
if int(str(y)[:1]) == 1 and int(str(t)[1]) != 1 and len(t) == 4 and t >1199:
print '{} {}/{}'.format(*t[1:])
if int(str(y)[:1]) != 1 and int(str(t)[1]) != 1 and len(t) == 3:
print '{} {}/{}'.format(*t)
if int(str(y)[:1]) != 1 and int(str(t)[1]) == 1 and len(t) == 3:
print '{} {}/{}'.format(*t)
else:
print(a)
Common Sample Inputs/Outputs (many more combos):
In: 4 3/4 | Out: 4 3/4
In: 4.75 | Out: 4.75
In: T 3/ | Out: 3
In: 14 3/4 | Out: 4 3/4 (leading 1 does not belong >11
In: 4 .33 | Out: 4.33
In: 3 2./3 | Out: 3 2/3
In: 3 ..33 | Out: 3.33
Essentially its a fraction if there is a '/' in the string even if it contains a '.'. If its not in the string, it's a decimal. If neither, then there is an opportunity there as well for some logic
Alright #FanScience, got an answer here. It works with all the inputs you gave, but it's slightly brittle -- happy to try to expand if you find there are inputs that it doesn't get along with.
First I imported two helpful libraries:
import re
from fractions import Fraction
Next I defined a dictionary with your inputs + expected outputs, so I could write a function that tested my methodology:
expected_results = {
"4 3/4": 4.75,
"4.75": 4.75,
"T 3/": 3,
"14 3/4": 4.75,
"4 .33": 4.33,
"3 2./3": 3.67,
"3 ..33": 3.33,
}
Next I got to writing the actual function -- let me know if you have any questions, as this is somewhat complex:
def generate_correct_float(to_convert):
# Removes any alphabetical character (A, B, a, b...)
to_convert = re.sub("[a-zA-Z]", "", elem)
# Removes extra whitespace on either end
to_convert = to_convert.strip()
final_answer = 0
if " " in to_convert: #two-part, ie 4 3/4
primary_number, secondary_number = to_convert.split()
final_answer += int(primary_number)
if "/" in secondary_number: # Fraction case
secondary_number = secondary_number.replace(".", "")
secondary_number = secondary_number.strip("/")
secondary_number = Fraction(secondary_number)
else: #Decimal Case
secondary_number = Fraction(int(secondary_number.replace(".", "")), 100)
final_answer += round(secondary_number.__float__(), 2)
else: # Single element, ie 3/
final_answer = to_convert.strip("/")
final_answer = float(final_answer)
# Eliminate cases where we're higher than 11
while final_answer > 11:
final_answer -= 10
return final_answer
Finally I wrote a wrapper function that tests inputs vs outputs and gives us a correct vs incorrect count:
incorrect = 0
for elem in expected_results:
answer = generate_correct_float(elem)
if answer != expected_results[elem]:
print('------')
print(elem)
print(expected_results[elem])
print(answer)
incorrect += 1
correct = len(expected_results) - incorrect
print(f"correct: {correct}")
print(f"incorrect: {incorrect}")
Running this with our code gives us 7/7, all with floats!
Hopefully this helps -- let me know if there are any points of clarification I can make #FanScience

Calculate the total resistance of a circuit given in a string

I have really been struggling to solve this problem. This is the problem:
Given a string describing the circuit, calculate the total resistance
of the circuit.
Here is an example:
input: 3 5 S
expected output: 8
The operands in the string are trailed by the operator, denoting if the resistors are either in Series or Parallel. However let's analyze a more complicated circuit:
input: 3 5 S 0 P 3 2 S P
expected output: 0
Step by step:
The 3 5 S at the beginning of the input gives us 8 and hence the first intermediate step is the string 8 0 P 3 2 S P.
8 0 P gives us 0, as one resistor is short-circuited and consequently we get 0 3 2 S P.
3 2 P is 5.
and finally 0 5 P is 0.
Here is my attempt. I tried using recursion as it seemed like a problem that can be solved that way. Firstly I wrote a helper function:
def new_resistance(a,b,c):
if c == '':
if int(a) == 0 or int(b) == 0:
return 0
else:
return 1/(1/int(a) + 1/int(b))
else:
return int(a) + int(b)
And the function that calculates the newn resistance of the circuit:
def resistance(array):
if isinstance(array, int):
return array
else:
if isinstance(array,list):
temp = array
else:
temp = array.split(" ")
i = 0
while True:
try:
a = new_resistance(temp[i], temp[i+1], temp[i+2])
except Exception as e:
i += 1
if len(temp[i+3:]) == 0:
return resistance(new_resistance(temp[i], temp[i+1], temp[i+2]))
else:
return resistance(temp[:i] + [new_resistance(temp[i], temp[i+1], temp[i+2])] + temp[i+3:])
The idea behind the program is to start at the beginning of the list and calculate the resistance of the first three elements of the list, then to append them at the beginning of a new list (without the three elements) and call the function again with the new list. Do this until only a single integer remains and return the integers.
Any help is appreciated.
UPDATE:
The solution to the problem, using a stack and a parser similar to a NPR parser.
operator_list = set('PS')
def resistance(circuit):
temp = circuit.split(" ")
stack = []
for char in temp:
if char in operator_list:
a = new_resistance(stack.pop(), stack.pop(), char)
print(a)
stack.append(a)
else:
print(char)
stack.append(char)
return stack[-1]
def new_resistance(a,b,c):
if c == 'P':
if float(a) == 0 or float(b) == 0:
return 0
else:
return 1/(1/float(a) + 1/float(b))
else:
return float(a) + float(b)
circuit = '3 5 S 0 P 3 2 S P'
resistance(circuit)
# 3
# 5
# 8.0
# 0
# 0
# 3
# 2
# 5.0
# 0
The problem is that once you reach 0 3 2 S P, you cannot simply take the first 3 elements. You need to look for number number S_or_P, wherever it is in the string.
You can use a regex for this task:
import re
circuit = '3 5 S 0 P 3 2 S P'
pattern = re.compile('(\d+) +(\d+) +([SP])')
def parallel_or_serie(m):
a, b, sp = m.groups()
if sp == 'S':
return str(int(a) + int(b))
else:
if a == '0' or b == '0':
return '0'
else:
return str(1/(1/int(a) + 1/int(b)))
while True:
print(circuit)
tmp = circuit
circuit = re.sub(pattern, parallel_or_serie, circuit, count=1)
if tmp == circuit:
break
# 3 5 S 0 P 3 2 S P
# 8 0 P 3 2 S P
# 0 3 2 S P
# 0 5 P
# 0
Note that 1 1 P will output 0.5. You could replace int by float and modify the regex in order to parse floats.
Your program, or more specifically your parser, seems to be relying on the Reverse Polish Notation, which in turn is a small variant of the Normal Polish Notation. Simply put, the RPN is an abstract representation where the operators of an arithmetical expression follow their operands, unlike in the Normal Polish Notation where the operators precede their operands. Parsers based on this representation can be easily implemented by using stacks (and usually do not need to interpret parentheses).
If you are tasked with developing that parser you may get some input from the Wikipedia article I linked above.
Credits to #none who first recognized the RPN.
Old memories came to my mind. I was playing with the FORTH language on 8-bit computers in 1980s. OK, back to Python:
circuit = '3 5 S 0 P 3 2 S P'
stack = []
for n in circuit.split():
if n == 'S':
r1 = stack.pop()
r2 = stack.pop()
stack.append(r1+r2)
elif n == 'P':
r1 = stack.pop()
r2 = stack.pop()
stack.append(0.0 if (r1 == 0 or r2 == 0) else 1/(1/r1+1/r2))
else:
stack.append(float(n))
assert len(stack) == 1
print(stack[0])
On in the spirit of VPfB for any combination of serial parallel (not only in pairs)
def calculateresistor(dataString):
stack = []
r = []
cicuit=dataString
for n in circuit.split():
if n == 'S':
stackSize=size(stack)
if size(stack)>=2:
for k in range(0,size(stack)-1):
r.append(float(stack.pop()))
r.append(float(stack.pop()))
stack.append((r[-1]+r[-2]))
elif n == 'P':
stackSize=size(stack)
if size(stack)>=2:
for k in range(0,size(stack)-1):
r.append(float(stack.pop()))
r.append(float(stack.pop()))
r.append(0.0 if (r[-1] == 0 or r[-2] == 0) else (1/(1/r[-1]+1/r[-2])))
stack.append(r[-1])
else:
stack.append(float(n))
assert len(stack) == 1
return(stack)

Categories

Resources