Displaying element in my text file when it is lesser than the range? - python-3.x

I am trying to create a Top 5 leaderboard for my game in Python 3.
Here's what I have
Top_Score = open("highscore.txt", "r+")
score_list = []
print(" Top 5")
print("==========")
for line in Top_Score.readlines(): # Read lines
score_list.append(line)
score_list.sort()
for i in range(5):
print("Pos", str(i + 1), ":", score_list[i])
print("==========")
Top_Score.close()
highscore.txt
50
18
20
40
50
60
70
Output
Top 5
==========
Pos 1 : 18
Pos 2 : 20
Pos 3 : 40
Pos 4 : 50
Pos 5 : 50
==========
But how can I display element in my text file if it is lesser than the range(5) without any errors? Any help would be appreciated
Example highscore.txt
50
18
20
Example Output
Top 5
==========
Pos 1 : 18
Pos 2 : 20
Pos 3 : 50
==========

In the print loop, you need to check if the size of the list is smaller than 5. If so, only loop until the size.
So, something like this:
loop_range = 5
if len(score_list) < loop_range:
loop_range = len(score_list)
for i in range(loop_range):
print("Pos", str(i + 1), ":", score_list[i])
This can be rewritten using the min function to select the smaller of the two numbers, 5 or the size:
loop_range = min(5, len(score_list))
for i in range(loop_range):
print("Pos", str(i + 1), ":", score_list[i])

Related

How to get sum of probabilities of rolling w dice where one is fair and the other one is unfair?

I am writing a little program and wanted to ask how I can add the logic of having an unfair dice in the game? Right now, my code produces the sum of probabilities of rolling 2 dices with 6 faces for i times. However, it is treating the dices with a 1/6 probability of rolling a given number. How do I tweak it, so that the unfair dice ONLY shows up in the range of 2-5 but never as 1 or 6? The output should the sum of probs for all numbers in range 2-12 given the fair and unfair dice.
import random
from collections import defaultdict
def main():
dice = 2
sides = 6
rolls = int(input("Enter the number of rolls to simulate: "))
result = roll(dice, sides, rolls)
maxH = 0
for i in range(dice, dice * sides + 1):
if result[i] / rolls > maxH: maxH = result[i] / rolls
for i in range(dice, dice * sides + 1):
print('{:2d}{:10d}{:8.2%} {}'.format(i, result[i], result[i] / rolls, '#' * int(result[i] / rolls / maxH * 40)))
def roll(dice, sides, rolls):
d = defaultdict(int)
for _ in range(rolls):
d[sum(random.randint(1, sides) for _ in range(dice))] += 1
return d
main()
Output
Enter the number of rolls to simulate: 10000
2 265 2.65% ######
3 567 5.67% #############
4 846 8.46% ####################
5 1166 11.66% ############################
6 1346 13.46% ################################
7 1635 16.35% ########################################
8 1397 13.97% ##################################
9 1130 11.30% ###########################
10 849 8.49% ####################
11 520 5.20% ############
12 279 2.79% ######
Given that the logic of which results are possible is currently being controlled by the line
random.randint(1, sides)
that's the line to change if you want to roll with different bounds. For example, to get 2-5, you could generalize the function:
def main():
dice = 2
sides = 6
unfair_min = 2
unfair_max = 5
rolls = int(input("Enter the number of rolls to simulate: "))
result_unfair = roll_biased(dice, sides, rolls, min_roll=unfair_min, max_roll=unfair_max)
maxH = max(result_unfair.values()) / rolls
for i in range(dice, dice * sides + 1):
print('{:2d}{:10d}{:8.2%} {}'.format(i, result_unfair[i], result_unfair[i] / rolls,
'#' * int(result_unfair[i] / rolls / maxH * 40)))
def roll_biased(dice, sides, rolls, min_roll=1, max_roll=None):
if max_roll is None:
max_roll = sides
d = defaultdict(int)
for _ in range(rolls):
d[sum(random.randint(min_roll, max_roll) for _ in range(dice))] += 1
return d
Which could print:
Enter the number of rolls to simulate: 10000
2 0 0.00%
3 0 0.00%
4 632 6.32% ##########
5 1231 12.31% ###################
6 1851 18.51% #############################
7 2480 24.80% ########################################
8 1873 18.73% ##############################
9 1296 12.96% ####################
10 637 6.37% ##########
11 0 0.00%
12 0 0.00%
You could also generalize this to arbitrary choices (or arbitrary weights) using random.choices() as such:
def roll_from_choices(dice, sides, rolls, allowed_rolls=None):
if allowed_rolls is None:
allowed_rolls = list(range(1, sides+1))
d = defaultdict(int)
for _ in range(rolls):
d[sum(random.choices(allowed_rolls, k=dice))] += 1
return d
which you can call as:
result_unfair = roll_from_choices(dice, sides, rolls, allowed_rolls=[2, 3, 4, 5])
I would start with a single function that returns the result of a die(a) roll, where the options available can be tailored to exclude the impossible, something like:
import random
def throw_die(options):
return random.choice(options)
Then I would code for the generalised case where you can have any number of dice, each of varying abilities (to be passed as the options when throwing the die). In your particular case, that would be two dice with the second excluding 1 and 6(b):
dice = [
[1, 2, 3, 4, 5, 6],
[ 2, 3, 4, 5 ]
]
Then allocate enough storage for the results (I've wasted a small amount of space here to ensure code for collecting data is much simpler):
min_res = sum([min(die) for die in dice]) # Smallest possible result,
max_res = sum([max(die) for die in dice]) # and largest.
count = [0] * (max_res + 1) # Allocate space + extra.
Your data collection is then the relatively simple (I've hard-coded the roll count here rather than use input, but you can put that back in):
rolls = 10000 # rolls = int(input("How many rolls? "))
for _ in range(rolls):
# Throw each die, sum the results, then increment correct count.
result = sum([throw_die(die) for die in dice])
count[result] += 1
And the data output can be done as (rounding rather than truncating so that highest count has forty hashes - that's just my CDO(c) nature kicking in):
hash_mult = 40 / max(count)
for i in range(min_res, max_res + 1):
per_unit = count[i] / rolls
hashes = "#" * int(count[i] * hash_mult + 0.5)
print(f"{i:2d}{count[i]:10d}{per_unit:8.2%} {hashes}")
The complete program then becomes:
import random
# Throw a single die.
def throw_die(options):
return random.choice(options)
# Define all dice here as list of lists.
# No zero/negative number allowed, will
# probably break code :-)
dice = [
[1, 2, 3, 4, 5, 6],
[ 2, 3, 4, 5 ]
]
# Get smallest/largest possible result.
min_res = sum([min(die) for die in dice])
max_res = sum([max(die) for die in dice])
# Some elements wasted (always zero) to simplify later code.
# Example: throwing three normal dice cannot give 0, 1, or 2.
count = [0] * (max_res + 1)
# Do the rolls and collect results.
rolls = 10000
for _ in range(rolls):
result = sum([throw_die(die) for die in dice])
count[result] += 1
# Output all possible results.
hash_mult = 40 / max(count)
for i in range(min_res, max_res + 1):
per_unit = count[i] / rolls
hashes = "#" * int(count[i] * hash_mult + 0.5)
print(f"{i:2d}{count[i]:10d}{per_unit:8.2%} {hashes}")
and a few sample runs to see it in action:
pax:/mnt/c/Users/Pax/Documents/wsl> python prog.py
3 418 4.18% #########
4 851 8.51% ####################
5 1266 12.66% ##############################
6 1681 16.81% ########################################
7 1606 16.06% ######################################
8 1669 16.69% #######################################
9 1228 12.28% #############################
10 867 8.67% ####################
11 414 4.14% #########
pax:/mnt/c/Users/Pax/Documents/wsl> python prog.py
3 450 4.50% ##########
4 825 8.25% ###################
5 1206 12.06% ############################
6 1655 16.55% #######################################
7 1679 16.79% ########################################
8 1657 16.57% #######################################
9 1304 13.04% ###############################
10 826 8.26% ###################
11 398 3.98% #########
pax:/mnt/c/Users/Pax/Documents/wsl> python prog.py
3 394 3.94% #########
4 838 8.38% ####################
5 1271 12.71% ##############################
6 1617 16.17% ######################################
7 1656 16.56% #######################################
8 1669 16.69% ########################################
9 1255 12.55% ##############################
10 835 8.35% ####################
11 465 4.65% ###########
Footnotes:
(a) Using the correct nomenclature for singular die and multiple dice, in case any non-English speakers are confused.
(b) You could also handle cases like [1, 2, 3, 4, 4, 5, 6] where you're twice as likely to get a 4 as any other numbers. Anything much more complex than that would probably better be handled with a tuple representing each possible result and its relative likelihood. Probably a little too complex to put in a footnote (given it's not a requirement of the question) but you can always ask about this in a separate question if you're interested.
(c) Just like OCD but in the Correct Damn Order :-)

Python(AI Constraint satisfaction problem) Fitting square and/or rectangular (2d) tiles onto a rectangular ground

I have to arrange and/or fit 2d tiles into a 2d square or rectangular plane with AI algorithm using python program. Each tile has a length and width. For example if a plane is 4x3 and set of tiles is
S={(2,3),(1,2),(2,2)}
these tiles can be rotated 90 degrees in order to fit the matrix.
input
first line contains length and width of the plane
second line number of tiles
and then the length,width of the subsequent tiles
but the inputs should be tab seperated
for eg
4 3
3
2 3
1 2
2 2
output
for eg
1 1 2 2
1 1 3 3
1 1 3 3
I have trouble solving this as i have to use only standard libraries in python no NumPy and no CSP library
~Edit 2`
my code so far I cant figure out how to add algorithm without csp library or to generate grid
from sys import stdin
a = stdin.readline()
x = a.split()
rectangular_plane = [[0] * int(x[0]) for i in range(int(x[1]))]
num_of_rectangles = stdin.readline()
r_widths = []
r_lengths= []
for l in range(int(num_of_rectangles)):
b = stdin.readline()
y = b.split()
r_lengths.insert(l,y[0])
r_widths.insert(l,y[1])
I've solved task with backtracking approach and without any non-standard modules.
Try it online!
import sys
nums = list(map(int, sys.stdin.read().split()))
pw, ph = nums[0:2]
ts = list(zip(nums[3::2], nums[4::2]))
assert len(ts) == nums[2]
if sum([e[0] * e[1] for e in ts]) != pw * ph:
print('Not possible!')
else:
def Solve(*, it = 0, p = None):
if p is None:
p = [[0] * pw for i in range(ph)]
if it >= len(ts):
for e0 in p:
for e1 in e0:
print(e1, end = ' ')
print()
return True
for tw, th in [(ts[it][0], ts[it][1]), (ts[it][1], ts[it][0])]:
zw = [0] * tw
ow = [it + 1] * tw
for i in range(ph - th + 1):
for j in range(pw - tw + 1):
if all(p[k][j : j + tw] == zw for k in range(i, i + th)):
for k in range(i, i + th):
p[k][j : j + tw] = ow
if Solve(it = it + 1, p = p):
return True
for k in range(i, i + th):
p[k][j : j + tw] = zw
return False
if not Solve():
print('Not possible!')
Example input:
4 3
3
2 3
1 2
2 2
Output:
1 1 2 2
1 1 3 3
1 1 3 3

print results to text file in tabular form

I am currently printing onto console, can I print the output onto a text file in tabular form?
I am trying to write the file with:
with open("increment.txt", "w") as file:
file.write(i, mol)
file.close()
Here is the program:
import numpy as np
i: int
for i in range(1, 100,5):
mol = int((i*5)/(i+2))
print('i & mol are:',i, mol)
with open("incre.txt", "w") as file:
file.write(i, mol)
file.close()
Error message..
file.write(i, mol)
TypeError: write() argument must be str, not tuple
You are defining mol inside of your loop; here is the corrected code as far as I understand your question:
with open("incre.txt", "w") as file:
for i in range(1, 100, 5):
mol = int((i * 5) / (i + 2))
file.write(str(i) + " " + str(mol))
file.close()
This will write your i variable separated by a space, then your mol variable. Note since you haven't specified an output directory, it will create the file wherever your python script is stored.
Here is a more pythonic approach:
def write_example(output_path):
with open(output_path, "w") as file:
for i in range(1, 100, 5):
mol = int((i * 5) / (i + 2))
file.write(str(i) + " " + str(mol) + "\n")
file.close()
outpath = "/home/some_path_here/test.txt"
write_example(outpath)
This produces a txt file with the following contents:
1 1
6 3
11 4
16 4
21 4
26 4
31 4
36 4
41 4
46 4
51 4
56 4
61 4
66 4
71 4
76 4
81 4
86 4
91 4
96 4
Each of these being on a new line.
Let me know if this helped! Cheers!

How can I generate random numbers in slabs of a range in Python3 or in a specific interval of range in Python3?

Suppose I want to generate 10 random numbers between 1 to 100. But I want to pick numbers randomly from each number of sets like 1-10, 11-20, 21-30,.... So that It does not come out like this: 1, 7, 26, 29, 51, 56, 59, 89, 92, 95.
I want to pick numbers randomly like this: 7, 14, 22, 39, 45, 58, 64, 76, 87, 93.
I have created a code sample. But I can't figure out later part of the problem.
import random
def getInteger(prompt):
result = int(input(prompt))
return result
range1 = getInteger("Please Enter Initial Range: ")
range2 = getInteger("Please Enter Ending Range: ")
range3 = getInteger("Please Enter the Range size: ")
myList = random.sample(range(range1, range2), range3)
myList.sort()
print ("Random List is here: ", myList)
I am new to programming. I googled about it, but did not find any solution. Thank you guys in advance...
In your case, you need to pick 10 times a random number between 0 and 9 and add 10 in each step.
import random
random_numbers = []
for i in range(0, 10):
random_number = random.randrange(10) # pick a number between 0-9
random_number += 10*i # add 10 in each iteration
random_numbers.append(random_number)
print(random_numbers)
EDIT:
if you want to set your own values, this could work:
import random
random_numbers = []
begin = 100
end = 200
interval = 10
for i in range(0, round((end-begin)/interval)):
random_number = random.randrange(interval)
random_number += round(interval)*i + begin
random_numbers.append(random_number)
print(random_numbers)
Consider using random.choice and a for loop:
>>> for i in range(1, 100, 10):
... print(random.choice(range(i, i + 10)))
...
10
19
21
34
45
51
68
74
88
98
>>> for i in range(1, 100, 10):
... print(random.choice(range(i, i + 10)))
...
6
14
30
37
50
56
65
79
85
94
You could use this:
import random
start = 1
stop = 100
interval = 10
ran = [random.choice( range(start + i*interval, start + (i+1)*interval-1))
for i in range(len(range(start,stop,interval)))]
print(ran)
Explanation:
the i is selected from 0 to len(...) of how many intervals you would get by using start to stop with/by interval
For this examble it returns 10 which results in numbers for i from 0 to 9.
The random.choice uses this i to compute/chunk up the whole number-range from start to stop in chunks of intervals size - choice then draws one of the numbers in this subrange for your resulting list.
range(start + i*interval, start + (i+1)*interval-1)
# evaluaters to
# i = 0: 1+0, 1+(0+1)*10-1 = 1,10
# i = 1: 1+10, 1+(1+1)*10-1 = 11,20
# etc.
Edit:
This might overshoot on the upper limit - which is fixable by using
ran = [random.choice( range(start + i*interval,min(stop, start + (i+1)*interval-1))) for i in range(len(range(start,stop,interval)))]
which limits the upper bound by using min(stop, calculated end)

Python3 Extracting lines between first instance of two markers

I imported a text file from URL and want to process it. The file looks as below. There are two instances of " innings " and "Extras ". I want to extract lines between the FIRST instance of " innings " and FIRST instance of "Extras ". The code that I wrote extracts ALL instances. How do I resolve this?
Toss: Sri Lanka Umpires: M Erasmus (South Africa) and NJ Llong
(England) TV umpire: S Ravi (India) Match referee: DC Boon
(Australia) Reserve umpire: SD Fry (Australia) Player of the
match: CJ Anderson New Zealand innings (50 overs maximum)
R M B 4 6 MJ Guptill c Sangakkara b Lakmal
49 94 62 5 0 CJ Anderson c Lakmal b
Kulasekara 75 77 46 8 2
+L Ronchi not out 29 29 19 4 0
Extras (lb 2, w 8, nb 3) 13 Total (6 wickets, 50 overs, 226 mins) 331
Sri Lanka innings (target: 332 runs from 50 overs) R
M B 4 6 HDRL Thirimanne b Boult
65 90 60 8 0 RAS Lakmal not out
7 21 17 0 0
Extras (w 10, nb 1) 11 Total (all out, 46.1 overs, 210 mins) 233
Here is my code:
flag = 1
for line in data:
if " innings " in line:
flag = 0
print('')
if line.startswith("Extras "):
flag = 1
print('')
if not flag and not " innings " in line:
print(line)
Your program must stop on the first occurrence of Extras:
active = False # A variable `flag` is not very precisely named,
# better call it `active`, make it boolean
# and flip the values
for line in data:
if " innings " in line:
active = True # now we want to do things
print('')
continue # but not in this loop
if line.startswith("Extras "):
print('')
break # now we're done!
# alternative Method:
# active = False
if active:
print(line)
If you want to store all occurrences:
active = False
stored = []
for line in data:
if " innings " in line:
tmp = []
active = True # now we want to do things
continue # but not in this loop
if line.startswith("Extras "):
stored.append(tmp)
active = False
continue
if active:
tmp.append(line)
You'll end up with a list of lists of lines for further processing.

Resources