I'm coding a program that reads a line in a file and determines whether or not the line makes a Lo Shu Magic square. In this magic square, the sum of the rows, sum of the columns, and sum of the diagonals have to equal 15, and each number 1-9 can only occur once in the square. This is what I have so far:
def main():
for line in open("Magic Square Input.txt"):
items = line.split(" ")
items = [int(x) for x in items]
result = [items[0:3], items[3:6], items[6:9]]
isMagic(result)
def isMagic(result):
checks1 = ''
for x in result:
for y in range(3):
if sum (result[y][y] for y in range(3)) == 15:
if sum(x[y] for x in result) == 15:
checks1 = checkDupe(result)
else:
checks1 = 'Invalid'
else:
checks1 = 'Invalid'
print(checks1)
def checkDupe(result):
checks1 = ''
for i in range(0,8):
counter = 0
for j in result:
if (j == i):
counter += 1
if counter > 0:
checks1 = 'Invalid'
else:
checks1 = 'Valid'
return checks1
main()
the contents of my text file are as follows:
4 3 8 9 5 1 2 7 6
8 3 4 1 5 9 6 7 2
6 1 8 7 5 3 2 9 4
6 9 8 7 5 3 2 1 4
6 1 8 7 5 3 2 1 4
6 1 3 2 9 4 8 7 5
5 5 5 5 5 5 5 5 5
The first three numbers in each line represent the top row of the square, the next three are the middle row, and the last three are the bottom row. The problem im having is that the first three squares ARE valid, and the last four are supposed to be invalid. But what my code keeps printing out for me is
Valid
Valid
Valid
Valid
Valid
Invalid
Valid
Could somebody show me where I'm screwing up here? I'm fairly new to python and I've been staring at this for hours trying to make sense of it.
This problem is much easier to think about if you start with a flat list:
[4, 3, 8, 9, 5, 1, 2, 7, 6]
and then work out which indexes you need to check. There are only eight in all:
indexes = (
(0, 1, 2), (3, 4, 5), (6, 7, 8), # rows
(0, 3, 6), (1, 4, 7), (2, 5, 8), # cols
(0, 4, 8), (2, 4, 6), # diag
)
With that set up, the check function becomes very simple:
def main():
for line in open('Magic Square Input.txt'):
square = [int(n) for n in line.split()]
if len(set(square)) != len(square):
print('Invalid: Duplicates')
else:
for idx in indexes:
if sum(square[i] for i in idx) != 15:
print('Invalid: Sum')
break
else:
print('Valid')
My version without spliting items into rows
data = '''4 3 8 9 5 1 2 7 6
8 3 4 1 5 9 6 7 2
6 1 8 7 5 3 2 9 4
6 9 8 7 5 3 2 1 4
6 1 8 7 5 3 2 1 4
6 1 3 2 9 4 8 7 5
5 5 5 5 5 5 5 5 5'''
def main():
for line in data.split("\n"):
# create list with all numbers
items = list(map(int, line.split()))
print(is_magic(items))
def is_magic(items):
# --- dups ---
#print('dups')
#print(len(set(items)) == 9)
#for x in range(1, 10):
# print(x, x in items)
if len(set(items)) != 9:
return 'Invalid'
# --- rows ---
#print('rows')
for x in range(0, 9, 3):
l = items[x:x+3]
#print(l, sum(l) == 15)
if sum(l) != 15:
return 'Invalid'
# --- cols ---
#print('cols')
for x in range(3):
l = [items[x], items[x+3], items[x+6]]
#print(l, sum(l) == 15)
if sum(l) != 15:
return 'Invalid'
# --- diags ---
#print('diags')
l = [items[0], items[4], items[8]]
#print(l, sum(l) == 15)
if sum(l) != 15:
return 'Invalid'
l = [items[2], items[4], items[6]]
#print(l, sum(l) == 15)
if sum(l) != 15:
return 'Invalid'
# --- OK ---
return 'Valid'
main()
def magic_square(n):
num=(n*((n*n)+1))/2
print('\nThe Magic Number Is:-',num,'\n')
f=[]
for i in range(0,n):
a=[]
for j in range(0,n):
a.append(0)
f.append(a)
(x,i,p,q)=(n*n,1,int(n/2),n-1)
while x!=0:
if x==0:
(f[p][q],i,p,q,x)=(i,i+1,p-1,q+1,x-1)
continue
else:
if p==-1 and q==n:
p=0
q=n-2
if f[p][q]==0:
(f[p][q],i,p,q,x)=(i,i+1,p-1,q+1,x-1)
continue
else:
p=p+1
q=q-2
f[p][q]=i
i=i+1
p=p-1
q=q+1
x=x-1
continue
if p==-1:
p=n-1
if f[p][q]==0:
(f[p][q],i,p,q,x)=(i,i+1,p-1,q+1,x-1)
continue
else:
p=p+1
q=q-2
f[p][q]=i
i=i+1
p=p-1
q=q+1
x=x-1
continue
if q==n:
q=0
if f[p][q]==0:
(f[p][q],i,p,q,x)=(i,i+1,p-1,q+1,x-1)
continue
else:
p=p+1
q=q-2
f[p][q]=i
i=i+1
p=p-1
q=q+1
x=x-1
continue
else:
if f[p][q]==0:
(f[p][q],i,p,q,x)=(i,i+1,p-1,q+1,x-1)
continue
else:
p=p+1
q=q-2
f[p][q]=i
i=i+1
p=p-1
q=q+1
x=x-1
continue
for i in range(len(f)):
for j in range(len(f[i])):
print(f[i][j] ,end = " ")
print("\n")
INPUT
magic_square(5)
OUTPUT
The Magic Number Is:- 65.0
9 3 22 16 15
2 21 20 14 8
25 19 13 7 1
18 12 6 5 24
11 10 4 23 17
In order to help you, I should start saying that your code is very difficult to read. Since you are new to Python, soon you will find out that one of the major benefits of Python is its clear syntax, which makes very easy to figure out what a piece of code is doing. That being said, I solve your problem, using the same logic as you did, but making the code more readable and using some of Python tricks to make the solution shorter and cleaner.
def main():
"""Open the file, parse the input and check if it is a magic cube"""
with open("Magic Square Input.txt") as f:
for line in f.readlines():
numbers = line.split(" ")
cube = [int(x) for x in numbers]
is_magic(cube)
def is_magic(cube):
"""Check if cube is magic.
There are two conditions that must be satisfied:
1 - There must not be any repetitions of the numbers
2 - All vertical/horizontal/diagonal sums must be 15
"""
if not dupe(cube) and check_sum(cube):
print ('Valid')
else:
print ('Invalid')
def dupe(cube):
"""Check if there are repetitions in the cube."""
if len(cube) == len(set(cube)):
return False
return True
def check_sum(cube):
"""Check if all vertical/horizontal/diagonal sums are 15"""
if vertical_check(cube) and horizontal_check(cube) and diagonal_check(cube):
return True
def vertical_check(cube):
if sum(cube[0:9:3]) == sum(cube[1:9:3]) == sum(cube[2:9:3]) == 15:
return True
return False
def horizontal_check(cube):
if sum(cube[0:3]) == sum(cube[3:6]) == sum(cube[6:9]) == 15:
return True
return False
def diagonal_check(cube):
if sum(cube[0:9:4]) == sum(cube[2:7:2]) == 15:
return True
return False
main()
I hope you can understand the solution from the comments in the code. If this is not the case, please post here again.
I had to make some major changes, but it seemed like your checkDupe method wasn't working right. You also only checked for one diagonal instead of both. Also, note that instead of saving whether the answer is valid or not using a checks1 variable, it simply returns 'Invalid' if anything is wrong, this generally makes code much cleaner and simplified the problem quite a bit. If 'Invalid' is never returned, then the method just returns 'Valid' at the end.
def main():
for line in open("Magic Square Input.txt"):
items = line.split(" ")
items = [int(x) for x in items]
result = [items[0:3], items[3:6], items[6:9]]
print isMagic(result)
def isMagic(result):
# check duplicates
if(checkDupe(result) == 'Invalid'):
return 'Invalid'
# diagonals
if sum (result[y][y] for y in range(3)) != 15:
return 'Invalid'
# other digonals
if sum (result[2 - y][2 - y] for y in range(3)) != 15:
return 'Invalid'
# rows and columns
for i in range(3):
if sum(result[i][y] for y in range(3)) != 15:
return 'Invalid'
if sum(result[x][i] for x in range(3)) != 15:
return 'Invalid'
return 'Valid'
def checkDupe(result):
for x in range(1,9):
if(not x in (result[0]+result[1]+result[2])):
return 'Invalid'
return 'Valid'
main()
Here I have created sample method to solve this issue. In this method, we are maintaining following lists
lstAvailableNumbers: list of available numbers (in your case it would be 1-9)
lstTraversedNumbers: list of traversed numbers (once a item is traversed, it is moved to this list)
list of duplicate numbers (all the duplicate numbers will be added to this list)
duplicate number index (it will store the index of the duplicate number so that it can used to replace the non-existing number
It also return the cost of replacement
For debugging purpose, I have also added print statement to check the value of different list
def createMagicSquare(s):
lstAvailableNumbers = list()
lstAvailableNumbers=[1,2,3,4,5,6,7,8,9]
lstTraversedNumbers=set()
lstDuplicateNumbers=list()
dictDuplicateNumberIndex = dict()
lstMissingNumbers=set()
cost=0
for item in range(len(s)):
for colItem in range(len(s[item])):
num= s[item][colItem]
#print('Print traversed number - ' )
#print(num)
#print(lstTraversedNumbers)
if(num in lstAvailableNumbers):
#print('Inside if condition for num in lstAvailableNumbers ' )
lstAvailableNumbers.remove(num)
#print(num)
if(num in lstTraversedNumbers):
#print('Inside if condition for num in lstTraversedNumbers ' )
#print(num)
lstDuplicateNumbers.append(num)
lstIndexPosition =[]
lstIndexPosition.append(item)
lstIndexPosition.append(colItem)
dictDuplicateNumberIndex[num]=lstIndexPosition
lstTraversedNumbers.add(num)
#print(lstTraversedNumbers)
else:
lstDuplicateNumbers.append(num)
lstIndexPosition =[]
lstIndexPosition.append(item)
lstIndexPosition.append(colItem)
dictDuplicateNumberIndex[num]=lstIndexPosition
i=0
#print("Available Numbers -")
#print(lstAvailableNumbers)
#print("Traversed Numbers -")
#print(lstTraversedNumbers)
#print("Duplicate Numbers -")
#print(lstDuplicateNumbers)
#print("Duplicate Number index -")
#print(dictDuplicateNumberIndex)
for item in lstAvailableNumbers:
itemToReplace= lstDuplicateNumbers[i]
value= dictDuplicateNumberIndex[itemToReplace]
s[value[0]][value[1]] = item
i+=1
cost += abs(itemToReplace - item)
#print(cost)
return cost
Related
For example this is array = [1,2,3,4,3,2,1]
i want computer to choose i=4 and sum both left of the four and right of the four and then compare if they are equal to each other, program prints i value to the screen.
Now i write it in here and it works as long as the i value is 0 but if i want to make this search for i>0 then i gets complicated.
this is my main program:
# importing "array" for array creations
import array as arr
# Function to find sum
# of array exlcuding the
# range which has [a, b]
def sumexcludingrange(li, a, b): # I FOUND THIS FUNCTION ONLINE BUT ALSO DIDN`T WORK EITHER.
sum = 0
add = True
# loop in li
for no in li:
# if no != a then add
if no != a and add == True:
sum = sum + no
# mark when a and b are found
elif no == a:
add = False
elif no == b:
add = True
# print sum
return sum
#lis = [1, 2, 4, 5, 6]
#a = 2
#b = 5
#sumexcludingrange(arr, 0, i-1)
def my(arr):
for i in range(len(arr)):
if i == 0: #this works when array is like [1,0,0,1] and i equals zero
sum_left = arr[0]
sum_right = sum(arr) - arr[0]
while sum_left == sum_right:
print(i)
break
elif i > 0 : # i 1 2 3 4 5 6 7 8 9..
#sumleft and sumright are not right.. what is the issue here?
sum_left = sumexcludingrange(arr, 0, i-1) #result is 16, sumexcludingrange function didn`t
#work.
print (sum_left)
#print(i)
sum_right == sum(arr) - sum_left
#print(sum_right)
#break
while sum_left == sum_right:
print(sum_left)
print(sum_right)
print("they are equal now")
break
else:
print("index cannot be a negative number.")
something = arr.array('i', [1,2,3,4,3,2,1]) # len(arr) = 7
my(something)
After seeing that i need another function to compare two sides of the array, i created a new file and write it in here and somehow it outputs this:
1
13
13
2
10
10
#array[i] array[i+1] .. + array[length-1]
array = [1,2,3,4,5,6,7] # 7 element so length=7,
for i in range(len(array)):
if i > 0 :
ln = len(array) + 1
sum_right = sum(array[i+1:ln])
sum_left = sum(array) - sum_right
print(i)
print(sum_right)
print(sum_right)
the way i think is this:
# array[i] i>0 i={1,2,3,4..}
sum_total = sum(arr) = array[0] + ..+ array[i-1] + array[i] + array[i+1] + ... + array[length-1]
sum_right = array[i+1] + .. + array[length-1]
sum_left = sum_total - sum_right
Is there a better way to accomplish that?
If I understand your question correctly, the solution could be something like this:
array = [1,2,3,4,5,6,7]
a1 = array[:4] # first 4 numbers
a2 = array[-4:] # last 4 numbers
total = sum(array)
diff = total-sum(a2)
I need the numbers from 1-100 which does not having the digit 1 and 7, eg 0,2,3,4,5,6,8,9,22,23,24,25 so on. Below is the sample code to find the Number which contain the digit d. I need to modify according to my requirement.
def isDigitPresent(x, d):
# Breal loop if d is present as digit
while (x > 0):
if (x % 10 == d):
break
x = x / 10
# If loop broke
return (x > 0)
# function to display the values
def printNumbers(n, d):
# Check all numbers one by one
for i in range(0, n+1):
# checking for digit
if (i = d or isDigitPresent(i, d)):
print(i,end=" ")
# Driver code
n = 500
d = 0
print("The number of values are")
printNumbers(n, d)
It's a lot easier if you convert the integer into a string and check just check if '7' or '1' are in the string. If not, print it.
def printNumbers(n):
for i in range(0, n + 1):
str_int = str(i)
if not '7' in str_int and not '1' in str_int:
print(i, end=" ")
# Driver code
n = 500
print("The number of values are")
printNumbers(n)
returns
The number of values are
0 2 3 4 5 6 8 9 20 22 23 24 25 26 28 29 30 32 33 ...
You can create a function that checks a digit individually.
def not_contain(num):
nums = list(str(num))
res = [i for i in nums if i not in ['1', '7']]
return True if len(res) == len(nums) else False
Then use filter() to get the results you want.
mylist = [i for i in range(101)]
res = list(filter(not_contain, mylist))
# [0, 2, 3, 4, 5, 6, 8, 9 ------, 99]
Here's modifying your way to work:
def isDigitPresent(x, d):
# Breal loop if d is present as digit
while x > 0:
if int(x % 10) in set(d):
return True
x //= 10
return False
def printNumbers(n, d):
# Check all numbers one by one
for i in range(0, n + 1):
# checking for digit
if not isDigitPresent(i, d):
print(i, end=" ")
# Driver code
n = 500
d = [1, 7]
print("The number of values are")
printNumbers(n, d)
I tried to solve Project Euler #37:
The number 3797 has an interesting property. Being prime itself, it is possible to continuously remove digits from left to right, and remain prime at each stage: 3797, 797, 97, and 7. Similarly we can work from right to left: 3797, 379, 37, and 3.
Find the sum of the only eleven primes that are both truncatable from left to right and right to left.
NOTE: 2, 3, 5, and 7 are not considered to be truncatable primes.
I wrote my code in Python but I am facing weird issues.
Here's my code:
def isPrime(n):
if n == 2 or n == 3 or n == 5: return True
if n < 2 or n%2 == 0: return False
if n < 9: return True
if n%3 == 0: return False
if n%5 == 0: return False
r = int(n**0.5)
f = 5
while f <= r:
if n%f == 0: return False
if n%(f+2) == 0: return False
f +=6
return True
def gen(nb):
results = []
nb_str = str(nb)
for k in range(0, len(nb_str) - 1):
results.append(nb_str[k:])
results.append(nb_str[-k:])
return results
def check(nb):
for t in gen(nb):
if not isPrime(int(t)):
return False
return True
c = 0
s = 0
i = 2
while c != 11:
if check(i):
c += 1
s += i
i += 1
print(s)
Where does the error come from? (The expected result is 748317)
I suspect the errors coming from the results list
Yes, the gen() function is not working correctly as your slicing is off, also, you count 2, 3, 5 and 7 as truncatable primes which the question denies.
The second slice should be the other way around:
>>> s = 'abcd'
>>> for i in range(1,len(s)-1):
... print(s[i:])
... print(s[:-i])
...
bcd
abc
cd
ab
which we can see produces the right strings.
Altogether then, the function should be:
def gen(nb):
results = [nb]
nb_str = str(nb)
for k in range(1, len(nb_str)):
results.append(int(nb_str[k:]))
results.append(int(nb_str[:-k]))
return results
note I also added a string to int conversion - not sure how Python didn't make that obvious for you :/
And before get the full solution, Project Euler nearly always gives you an example which you can use to check your code:
>>> check(3797)
True
You must also add a condition in the check function to return False if the number is 2, 3, 5 or 7 as this is stated clearly in the question.
And the result is the expected: 748317.
Joe Iddon has explained the error in your code, but you can speed it up a little by turning gen into an actual generator. That way, you can stop checking the results for a given nb as soon as you detect a composite number (and gen will stop generating them). I've also made a few minor tweaks to your primality tester. Remember, the or operator short-circuits, so if a is True-ish in a or b then it doesn't bother evaluating b.
def isPrime(n):
if n in {2, 3, 5, 7}:
return True
if n < 2 or n%2 == 0:
return False
if n%3 == 0 or n%5 == 0:
return False
r = int(n**0.5)
f = 5
while f <= r:
if n%f == 0 or n%(f+2) == 0:
return False
f += 6
return True
def gen(nb):
yield nb
nb_str = str(nb)
for k in range(1, len(nb_str)):
yield int(nb_str[k:])
yield int(nb_str[:-k])
def check(nb):
for t in gen(nb):
if not isPrime(t):
return False
return True
c = s = 0
# Don't check single digit primes
i = 11
while c < 11:
if check(i):
c += 1
s += i
print(i)
i += 2
print('sum', s)
output
23
37
53
73
313
317
373
797
3137
3797
739397
sum 748317
In fact, you can get rid of the check function, and replace it with all, which also short-circuits, like or does. So you can replace the
if check(i):
with
if all(map(isPrime, gen(i))):
I am trying to produce a code that verifies whether or not a user input meets the criteria of a pascal triangle. I know how to go about inputting the number of lines and having it develop a pascal triangle, but I am having trouble figuring out how to get a user to input something like 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1, and having my program say whether it is a pascal triangle or not.
values = input("Enter the numbers: ").split()
pascals_triangle = list(map(list, values))
I know the first line could split the numbers, and the second line would assign the numbers into individual lists of a list. Every time I attempt to have the lists increase by 1 in every row, I get str/int errors. Once I get past this little road block, I should be able to figure out the rest of the code.
data = input("Enter values: ").split()
def pascal_triangle(data):
size = int(data[0])
n = 2 * size + 1
grid = [[0 for x in range(n)] for y in range(size)]
left = 1
for i in range(size, 0, -1):
grids = data[i].split(' ')
count = 0
for g in grids:
grid[i - 1][left + 2 * count] = int(g)
count += 1
left += 1
if count != i:
return False
left = 1
for i in range(size - 1, -1, -1):
if i == 0:
return grid[i][left] == 1
numbers = i + 1
count = 0
while count < numbers:
current = grid[i][left + count * 2]
upper_left = grid[i - 1][left - 1 + count * 2]
upper_right = grid[i - 1][left + 1 + count * 2]
if current != (upper_left + upper_right):
return False
count += 1
left += 1
return False
status = pascal_triangle(data)
if status:
print('It is a pascal triangle')
else:
print('It is not a pascal triangle')
So, in this code, why am I still not getting the accurate answers?
If you're trying to do this in some fancy way, like adapting the grouper recipe in the itertools docs to take an iterable of group sizes instead of a fixed group size… take a step back and write the "dumb" version first.—just write a loop.
First, split the whole string, the same way you split each line in your line-by-line version.
One thing: mapping list over your values won't do any good; that'll just turn, e.g., '23' into ['2', '3'], and there's not much good you can do with that. You want a list of numbers, which you're then going to break up into a rows (each row also being a list of numbers—the same row you got by mapping int over line.split() in your line-by-line version).
So, here's some pseudocode:
values = input("Enter the numbers: ").split()
nums = [int(value) for value in values]
size = 1
start = 0
while start < len(nums):
rownums = nums[start:start+size]
make sure len(rownums) == size
check rownums the same way you checked each line
update size and start
if you got here without seeing any errors, it's valid
One way to do this is to generate each row of Pascal's triangle, and use islice to grab a list of the current row length from the user data and see if the data matches the row.
from itertools import islice
def pascal():
""" Pascal's triangle generator """
a = [1]
while True:
yield a
#Generate next row from current row
a = [x + y for x, y in zip([0] + a, a + [0])]
def test_pascal(values):
it = map(int, values.split())
ok = True
for row in pascal():
data = list(islice(it, len(row)))
if not data:
break
if data != row:
ok = False
print('bad data', data, row)
break
return ok
# Test
values = '1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1'
print(test_pascal(values))
values = '1 1 1 1 2 1 1 3 3 1 1 4 6 5 1'
print(test_pascal(values))
output
True
bad data [1, 4, 6, 5, 1] [1, 4, 6, 4, 1]
False
What I need is to show how many integers that are less than N that are not dividable by 2,3 or 5. I have managed to get the list of numbers that are less than N and are not divisible by 2,3 or 5 but I cannot for the life of me get Python to actually count how many integers there are.
What I have so far is
N = int(input("\nPlease input a Number "))
if N < 0:
print("\nThere are no answers")
else:
for a in range(1,N+1,2):
if a%3 !=0:
if a%5 !=0:
Try this:
N = 20
counter = 0
for a in range(1, N):
if a%2 and a%3 and a%5:
counter += 1
The result will be in counter at the end of the loop. Or for a fancier version, adapted from #iCodez's answer:
sum(1 for x in range(1, N) if all((x%2, x%3, x%5)))
=> 6
Have you tried declaring a global variable and incrementing it?
i = 0
... if a % 5 != 0:
i += 1
print i
This can be done quite easily using a list comprehension, all, and len:
>>> num = int(input(':'))
:20
>>> [x for x in range(num) if all((x%2, x%3, x%5))]
[1, 7, 11, 13, 17, 19]
>>> len([x for x in range(num) if all((x%2, x%3, x%5))])
6
>>>