I'm very new to Python programming and I've been tasked by an online friend to write code to solve the following problem:
'imagine a board game and you have to roll 2 dices.Write a program to roll the dices 100 times and find out which value (of both dices) appears most'
My attempt below kind of works in the sense that I'm able to ascertain the max frequency of two dice faces added together but not the actual dice thrown.(e.g. the total '9' was the most frequently thrown).
I'm sure there are plenty of ways of accomplishing the above so do excuse my very first attempt at coding!
import random
results = []
freq_2 = 0
freq_3 = 0
freq_4 = 0
freq_5 = 0
freq_6 = 0
freq_7 = 0
freq_8 = 0
freq_9 = 0
freq_10 = 0
freq_11 = 0
freq_12 = 0
for i in range(100):
face1 = random.randrange(1,7)
face2 = random.randrange(1,7)
value = face1 + face2
if value == 2:
freq_2 += 1
if value == 3:
freq_3 += 1
if value == 4:
freq_4 += 1
if value == 5:
freq_5 += 1
if value == 6:
freq_6 += 1
if value == 7:
freq_7 += 1
if value == 8:
freq_8 += 1
if value == 9:
freq_9 += 1
if value == 10:
freq_10 += 1
if value == 11:
freq_11 += 1
if value == 12:
freq_12 += 1
results.append(freq_2)
results.append(freq_3)
results.append(freq_4)
results.append(freq_5)
results.append(freq_6)
results.append(freq_7)
results.append(freq_8)
results.append(freq_9)
results.append(freq_10)
results.append(freq_11)
results.append(freq_12)
print max(results)
print freq_2, freq_3, freq_4, freq_5, freq_6, freq_7, freq_8, freq_9, freq_10, freq_11, freq_12
collections provides Counter which makes this task easy:
from random import choice
from collections import Counter
dice = range(1,7)
freq = Counter([choice(dice) + choice(dice) for i in range(100)])
print freq
print freq.most_common(1)
I would redo much of it, reducing the amount of variables you're using.
rather than a separate variable for each freq_#, use a list:
freqs = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # 12 zeroes
for i in range(100):
face1 = random.randrange(1,7)
face2 = random.randrange(1,7)
value = face1 + face2
freqs[value] += 1
This way, you also will not have to individually append each freq_# to a list afterwards.
Once this list is filled with its values, you can use a few simple python calls to find the data you'd like:
'The most frequent throw was 9 and it occurred 21 times'
The most frequent throw will be the index with the highest number in the list.
max_freq = max(freqs) # amount of times this number was thrown
the number that was rolled will be represented by the index of the max
most_frequent_roll = freqs.indexOf(max_freq) # the number that was thrown that many times.
You don't need to write explicitly all the cases. For such a task python dictionaries are very useful.
I won't solve the problem for you, but give you a hint how you could implement this using dictionaries:
# define a dictionary to hold the counts (just for a single dice here)
counts = {nbr_dots: 0 for nbr_dots in range(1, 7)}
# this will look like {1:0, 2:0, ...}
# now whenever you get a certain count (say 2 here) you can increment the value of
# this count by 1 like so:
counts[2] += 1
# now counts looks like: {1:0, 2:1, ...}
If then you want to get the key (so the count) that appeared the most:
most_frequent = max(counts, key=lambda k: counts[k])
# and the number of times it appeared:
nbr_observations = counts[most_frequent]
Hope this minimal example helps to get you started.
The other answers are good, but if for some reason you don't want to use them, then here is a simple loop that does the job after you have calculated the result.
maximum = 0
for i in range(len(results)):
if results[i] > maximum:
maximum = results[i]
itemAt = i
print('The most frequent throw was: '+ str(results[itemAt]))
print('It occured %d times' % maximum)
What you must do to find the value of each die is you must compose another for loop which records when the value of each face is a certain number, and then increase the frequency of that value:
face_freq_2 = 0
face_freq_3 = 0
face_freq_4 = 0
face_freq_5 = 0
face_freq_6 = 0
face_freq_7 = 0
face_freq_8 = 0
face_freq_9 = 0
face_freq_10 = 0
face_freq_11 = 0
face_freq_12 = 0
for j in range(100):
face_value1 = random.randrange(1,7)
face_value2 = random.randrange(1,7)
value1 = face_value1
value2 = face_value2
if (value1 == value2) and (value1 == 1):
face_freq_2 += 1
if (value1 == 1 and value2 == 2) or (value1 == 2 and value2 == 1):
face_freq_3 += 1
if (value1 == value2) and (value1 == 2):
face_freq_4 += 1
elif (value1 == 1 and value2 == 3) or (value1 == 3 and value2 == 1):
face_freq_4 += 1
if (value1 == 1 and value2 == 4) or (value1 == 4 and value2 == 1):
face_freq_5 += 1
elif (value1 == 2 and value2 == 3) or (value1 == 3 and value2 == 2):
face_freq_5 += 1
if (value1 == value2 and value1 == 3):
face_freq_6 += 1
elif (value1 == 1 and value2 == 5) or (value1 == 5 and value2 == 1):
face_freq_6 += 1
elif (value1 == 2 and value2 == 4) or (value1 == 4 and value2 == 2):
face_freq_6 += 1
From this you get the picture of what you must do, for as the values increase you will need more elif statements in addition to the initial if statement. Yes, it is a bit tedious but it should yield the desired results.
Related
newbie here. I've been trying to find the least common multiple of the numbers 1 thru 10. My code so far
def smallest_multiple():
a = 0
while True:
a += 1
if a%1 == 0 and a%2 == 0 and a%3 == 0 and a%4 == 0 and a%5 == 0 and a%6 == 0 and a%7 == 0 and a%8 == 0 and a%9 == 0 and a%10 == 0:
return a
print(smallest_multiple())
My result is 2520, which seems to be correct. It is the smallest number that is divisible by the numbers 1 thru 10 without remainder. But is there a way to make the 5 line shorter (not that much modulus) by iterating over them? I've tried something like this
def smallest_multiple():
a = 0
while True:
a += 1
for i in range(1, 11):
if a % i == 0:
return a
print(smallest_multiple())
But that returns just 1, not 2520. Is there a way to make
if a%1 == 0 and a%2 == 0 and a%3 == 0 and a%4 == 0 and a%5 == 0 and a%6 == 0 and a%7 == 0 and a%8 == 0 and a%9 == 0 and a%10 == 0:
shorter?
You could change it to
if all([a%i == 0 for i in range(1,11)]):
All takes a list and returns True if everything in the list is True
This uses a simple list comprehension to go through numbers 1 through 10, and check if they are all True with a%i == 0
You could use all:
def smallest_multiple():
factors = [i for i in range(1, 11)]
a = 0
while True:
a += 1
if all([a % factor == 0 for factor in factors]):
return a
print(smallest_multiple())
Output
2520
UPDATE
As suggested by #PatrickHaugh you can avoid the creation of lists:
def smallest_multiple():
factors = range(1, 11)
a = 0
while True:
a += 1
if all(a % factor == 0 for factor in factors):
return a
print(smallest_multiple())
Output
2520
Speaking of one-liners ^^
Not an Infinity loop, though
import sys
next(i for i in xrange(1, sys.maxsize) if len([j for j in range(1,10) if i % j == 0]) == 9)
#=> 2520
And this is not the most efficient solution.
I edited this down. What testCraps(number) does is that it calls a function called quietCraps() that returns a 1 for a win and a 0 for a loss. testCraps(number) is supposed to run quietCraps() a number of times equal to (number), adding 1 to winCoutner if a 1 is returned and adding 1 to lossCounter if a 0 is returned.
def testCraps(number):
winCounter = 0
lossCounter = 0
for test in range(number):
testGame = quietCraps(value1 = 1)
if str(test) == "1":
winCounter = winCounter + 1
elif str(test) == "0":
lossCounter = lossCounter + 1
print("The amount of wins is " + str(winCounter))
print("The amount of losses is " + str(lossCounter))
Just to clarify, a win will return a 1 and a loss will return a 0. I konw that the counter in testCraps(number) is counting, but it will only go up to 1 for both counters. For example:
testCraps(5)
0
1
1
1
1
The amount of wins is 1
The amount of losses is 1
I'm sure the answer is pretty simple, but I'm at a loss. Can anyone help me? If I did anything wrong with my post, I'm sorry. This is my first time asking a question here.
for test in range(number):
testGame = quietCraps(value1 = 1)
if str(test) == "1":
winCounter = winCounter + 1
elif str(test) == "0":
lossCounter = lossCounter + 1
Here, winCounter is incremented when test == 1. This occurs once, as the for loop just goes up from 0 to number, and therefore both counters will have a result of 1. Are you trying to check testGame instead? That has a value of None because quietcraps() returns nothing.
def quietCraps():
crapsTotal = craps(2)
return crapsTotal
This way quietCraps() returns a value and can be checked. Also, no need for the value1 argument, as it isn't used. Similarly, no need to write craps(value1 = 2, just write craps(2)
for test in range(number):
testGame = quietCraps(value1 = 1)
if testGame == 1:
winCounter = winCounter + 1
elif testGame == 0:
lossCounter = lossCounter + 1
No need to convert the result to string, just check if the numbers match.
P.S
if value1 == 1 == True:
Just change this to if value1 == 1. No need to check if that is true, because that's what it's checking!
Today is my first day learning Python and have a question about 2-dimensional arrays. I need to create a 2 dimensional array but don't know the size of each of them. Is there something similar to the arraylist like in Java? Here's my code so you can see what I mean. It's for day 3 of last year's Advent of Code. So I guess a slight spoiler ahead if you haven't done it and want to see the way I'm thinking of setting it up.
f=open('directions.txt')
houses = [0][0]
rows = 0
column = 0
total = 0
for line in f:
for c in line:
if (str(c) == '^'):
rows += 1
houses[rows][column] += 1
elif (str(c) == '>'):
column += 1
houses[rows][column] +=1
elif (str(c)=='<'):
column -= 1
houses[rows][column-=1] +=1
else:
rows -= 1
houses[rows][column] +=1
Thanks for any help.
I believe you want something like this
houses = dict()
rows = 0
column = 0
total = 0
for line in f:
for c in line:
houses.setdefault(rows,dict())
houses[rows].setdefault(column, 0)
if (str(c) == '^'):
houses[rows][column] += 1
rows += 1
elif (str(c) == '>'):
houses[rows][column] +=1
column += 1
elif (str(c)=='<'):
houses[rows][column] +=1
column -= 1
else:
houses[rows][column] +=1
rows -= 1
So I'm trying to implement a ConnectFour game in python, and I'm having some trouble with counting the pieces (from a single player) that are lined up together in a row. My code:
class ConnectFour(object):
def __init__(self):
self.row=6
self.col=7
self.board = []
#initialize the board
for arow in range(self.row):
row = []
for acol in range(self.col):
row.append(None)
self.board.append(row)
#function for counting the number of the same pieces in a row
def count_it(self, row, column, step_row, step_col):
assert row >= 0 and row < 6 and column >= 0 and column < 7
assert step_row != 0 or step_col != 0
counter1 = 0
counter2 = 0
if self.board[row][column] == None:
return 0
elif self.board[row][column] == 1:
for i in range(6):
while self.board[row + (i*step_row)][column + (i*step_col)] == 1:
counter1 += 1
return counter1
else:
for i in range(6):
while self.board[row + (i * step_row)][column + (i*step_col)] == 2:
counter2 += 1
return counter2
When I input a location and "step" in my function, I would like to get the number of pieces player 1 or player 2 has lined up but when I enter:
x= ConnectFour()
x.board[5][6] = 1
x.board[4][6] = 1
x.count_it(5,6,-1,0)
I get no output.
There is no need for that while inside for: whenever the while condition is true, it will become an infinite loop since the body of that loop does not affect the condition, it just keeps incrementing a counter forever.
One approach would be a single while loop:
while self.board[row + (counter1*step_row)][column + (counter1*step_col)] == 1:
counter1 += 1
Another approach is to leave the for loop, but i and counter1 actually serve the same purpose:
for i in range(6):
if self.board[row + (i*step_row)][column + (i*step_col)] != 1:
break
counter1 += 1
In both cases, take care of array boundaries, either by some ifs, or by placing sentinels at the border of the array.
I've written a small piece of code that should detect if there are any matching characters in the same place in the 2 strings. If there is , the score in incremented by 1, if there is 2 or more consecutive matching characters , the score is incremented by 3, if there is no matching character, the score is decremented by 1.
The problem is though , when i try to run the code, it gives me a error: string index out of range.
What might be wrong ? thank you very much.
def pairwiseScore(seqA, seqB):
count = 0
score = 0
while count < len(seqA):
if seqA[count] == seqB[count]:
score = score + 1
count = count + 1
while seqA[count] == seqB[count]: # This is the line the error occurs
score = score + 3
count = count + 1
elif seqA[count] != seqB[count]:
score = score - 1
count = count + 1
return score
Do both strings have the same lenght? otherwise you should consider using something like:
while count < min(len(seqA), len(seqB)):
Also, the zip function might come in handy here to pair off the letters in each word. It is a python builtin. e.g.
def letter_score(s1, s2):
score = 0
previous_match = False
z = zip(s1, s2)
for pair in z:
if pair[0] == pair[1]:
if previous_match:
score += 3
else:
score += 1
previous_match = True
else:
score -= 1
previous_match = False
return score
Indexes are numberd 0 to n.
len(someString)
will give you n + 1.
Let's say that your string is length 10, and the indexes are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Your while loop checks the condition that count is < 10. So far so good.
Ok now let's say that count is equal to 9. Immediately within the first while loop, you increment count.
So now count = 10.
Now attempting to access someString[count] will give you an IndexError because the indices only go up to 9.
The error message says it: You're trying to access a character beyond the boundaries of your string. Consider this:
>>> s = "hello"
>>> len(s)
5
>>> s[4]
'o'
Now when (at the start of the first while loop) count is 1 below len(seqA), then you're incrementing count and then you're doing seqA[count] which will throw this exception.
Let's assume you're calling pairwisescore("a", "a"):
score = 0
count = 0
while count < len(seqA): # 0 < 1 --> OK
if seqA[count] == seqB[count]: # "a" == "a" --> OK
score = score + 1 # score = 1
count = count + 1 # count = 1
while seqA[count] == seqB[count]: # seqA[1] doesn't exist!
In the second while loop you must test that count is less than len(seqA):
while count < len(seqA) and seqA[count] == seqB[count]:
...
and, also there's possibly other bug: If the length of seqB is less than length of seqA, you'll again see runtime exception. so, you should change every occurence of count < len(seqA) with count < min(len(seqA), len(seqB)).
def pairwiseScore(seqA, seqB):
count = 0
score = 0
isOne = False
isTwoOrMore = False
while count < min(len(seqA), len(seqB)):
if seqA[count] == seqB[count]:
if isTwoOrMore:
score = score + 3
count = count + 1
else:
if isOne:
isTwoOrMore = True
score = score + 1
count = count + 1
isOne = True
elif seqA[count] != seqB[count]:
score = score - 1
count = count + 1
isOne = False
isTwoOrMore = False
return score
a = 'apple'
b = 'aplle'
print(pairwiseScore(a, b))
I think this one solve the problem, I added a "counting" bool variable. And to respond to the question, your program didn't compare the length of the second string.
while count < min(len(seqA), len(seqB)):
The problem is that you do this:
count = count + 1
Both before the inner while loop and at the end of it. But you then continue using seqA[count] before checking it against len(seqA) again - so, once it goes too high, Python will try to read past the end of seqA, and you'll get that error (when, if the condition had been checked again after incrementing, the loop would have ended).
Using a Python for loop will get around bugs like this, since Python will manage count for you:
for a,b in zip(seqA, seqB):
if a == b:
score += 1
You can implement the extra-points bit easily in this by keeping track of whether the previous character is a match, rather than trying to work out how many after this one are. A boolean variable last_matched that you keep updated would help with this.