Basic Sudoku checker - python

I am creating a basic sudoku checker with the help of Python.
However, the result is always displayed as 'False'.
The code is as follows:
list = [[1,2,3,4],
[2,4,1,3],
[3,1,4,2],
[4,3,2,1]]
def sudoku_check(list):
n = len(list)
digit = 1
while digit <= n:
row_count = 0
col_count = 0
v = 0
while v < n:
x = 0
while x < n:
print ("Check")
if digit == list[v][x]:
row_count = row_count + 1
if digit == list[x][v]:
col_count = col_count + 1
x = x + 1
v = v + 1
if col_count != 1 or row_count != 1:
return False
digit = digit + 1
return True
print (sudoku_check(list))
I am new to programming. Would appreciate your help on this.
Thanks

Alright, have a solution for you/can explain your problem #ShreyashKarnik!
The Problem:
The issue in code comes from the chunk below:
while digit <= n:
row_count = 0
col_count = 0
v = 0
while v < n:
x = 0
while x < n:
print ("Check")
if digit == sudo_board[v][x]:
row_count = row_count + 1
if digit == sudo_board[x][v]:
col_count = col_count + 1
x = x + 1
v = v + 1
if col_count != 1 or row_count != 1:
return False
So what exactly is this code doing? It's going through every cell in your sudoku board and looking for a digit. For the sake of explanation, let's say it's looking for the digit 1. It checks every cell in the entire board, and since 1 appears 4 times total, col_count and row_count will be 4 every time. You can verify this with a print statement if you'd like!
Since your false check is checking against the number 1, it's going to fail every time. So let's start looking for a fix!
Making Things Pythonic
"Pythonic means code that doesn't just get the syntax right but that follows the conventions of the Python community". You say you're new to programming, so learning the proper style of how to write python is important. You have a couple of issues in the code above:
Confusing variable names
Using while loops instead of for loops
Lack of code modularity
Let's start with the last comment, lack of modularity and fix the other things along the way. Determining if a Sudoku grid is valid is actually surprisingly complex -- it has three components.
1. Do all of the rows have the right number of digits?
2. Do all of the columns have the right number of digits?
3. Does the grid as a whole have the right number of digits?
3 is actually a factor of 1 and 2, which you figured out in your code -- nice! But it might make things easier to read if we broke the first and second bit of things into their own functions. How might those look? Let's do rows first. For our function, we'll check each row and confirm that it has the right number of digits.
Let's start with the row checker. All we have to do for that is the following:
def has_correct_number_rows(sudo_board):
# the set we create below is an unordered grouping of the numbers
# 1-4.
correct_set = set(range(1, len(sudo_board)))
for row in sudo_board:
# this if statement checks if our row contains values 1-4
if (correct_set != set(row)):
return False
return True
This will return True if the rows all contain the correct number of items, otherwise it will give false.
Next, the checking the correct number of columns. This is slightly more complicated, but still fairly simple:
def has_correct_number_cols(sudo_board):
correct_set = set(range(1, len(sudo_board) + 1))
for col_num in range(0, len(sudo_board)):
# col_set creates a set of the elements in a given column
col_set = set([row[col_num] for row in sudo_board])
if (correct_set != set(row)):
return False
return True
Same return values here.
Putting it all together
Now that you have these two functions, your final check is actually very easy. It's below:
def sudoku_check_peter(sudo_board):
correct_rows = has_correct_number_rows(sudo_board)
correct_cols = has_correct_number_cols(sudo_board)
# This last line returns True if both are true, otherwise
# False.
return correct_rows and correct_cols
This ended up being quite wordy which I apologize for -- happy to answer follow up questions or explain anything more! hope this helps.

Related

Happy Number from Python list

i am an absolute Beginner in Python and im trying to, find happy numbers from a given List. but it doesn't give anything back, i searched for a solution but i couldnt find one. My code is this :
a = [1,4,7,82]
def is_happy(a):
for i in range (len(a)):
sum = a[i]
for digit in str(a[i]):
sum = 0
while sum != 1 and sum !=4:
sum = sum + int(digit) ** 2
if sum ==1:
b.append(a[i])
return b
print(is_happy(a))
May you can help me. Thank you!
Converting the integers to strings in order to calculate the sum of squares is not a great idea - better to combine division and modulus. Write a discrete function to do that.
Then write a function that handles one value at a time. Call that multiple times - once for each item in your list.
Here's an approach you could use:
def ss(n):
r = 0
while n > 0:
d = n % 10
r += d * d
n //= 10
return r
def is_happy(n):
if n > 0:
while True:
if (n := ss(n)) == 1:
return True
if n == 4:
break
return False
a = [1, 4, 7, 82]
for n in a:
print(n, is_happy(n))
Output:
1 True
4 False
7 True
82 True
the indents of Python made me suffer..
my solution now looks like:
a = [8,2,7,82]
b = []
def is_happy(a):
for i in range (len(a)):
sum = a[i]
while sum!=1 and sum !=4:
tempsum = 0
for digit in str(sum):
tempsum += int(digit) ** 2
sum = tempsum
if sum == 1:
b.append(a[i])
return b
print(is_happy(a))
and works fine. Thanks for your help and suggestions
Eminos,
I will help with some suggestions.
In Python, white space is very important, and it takes some time for any newbie to get used to.
In for i in range (len(a)):, there is an extra space between "range" and "(". It could still run, but is not the preferred style, since it is defined as a range() function.
Code blocks need consistent spacing (left indent). Each level should be 2 or 4 spaces, with 4 spaces recommended by PEP8 (not tabs). The below examples have too many spaces in left indent.
sum = 0
sum = sum + int(digit) ** 2
b.append(a[i])
To calculate the squre of a number, it is not necessary to change data type from integer to string.
squared = a[i]**2
To keep track of your squared numbers list, try:
tally = 0
for i in range(len(a)):
squared = a[i]**2 # squares each number in list
tally += squared # keeps a running sum of squared numbers
Generally, I think a function like is_happy should return a true/false statement(s). So a sample returned list can be ["True", "False", "True", "True"] for your input example [1, 4, 7, 82].
More work to do, but hope that will get you started. :-)

traversing through a list using recursion

So I am new to recursion and I am trying to make a program where you can enter a list and python tests each integer (lets say 9 for example) and sees if the integer following it is doubled. So if I entered a list of 2 4 8 16 32, would return 4, and -5 -10 0 6 12 9 36, would return 2 because -5 followed by -10 is one and 6 followed by 12 is the second. This is the code I have so far. I feel like I am very close. but just a few thing stand in my way. Any help would be great!
L = []
def countDouble(L):
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
print(y[1])
print(y[0])
count = 0
y[0] += y[0]
# unsure of how to multiple y[0] by 2
if y[0]*2 == y[1]:
count += 1
else:
count += 0
#how would I traverse through the rest of the entered list using recursion?
print(count)
countDouble(L)
If you want/need to solve it using recursion, the following will do the trick:
def count_sequential_doubles(li, count=0):
return count_sequential_doubles(li[1:], count + int(li[0] * 2 == li[1])) if len(li) > 1 else count
I would suggest this recursive way:
def countDouble(L):
count = 0
if len(L) == 1:
return count
else:
if int(L[0])*2 == int(L[1]):
count += 1
return count + countDouble(L[1:])
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = countDouble(y)
print(count)
I urge you to read the entire answer, but in case you are not interested in tips, notes and the process of finding the solution, here are two solutions:
solution using recursion (not recommended):
x = input()
y = x.split(' ')
count = 0
def countDouble(i):
if(i+1 == len(y)):
return 'recursion ends here when'
if(int(y[i])*2==int(y[i+1])):
count += 1
countDouble(i+1)
countDouble(0)
print(count)
this solution just imitates a while loop:
solution using a while loop (recommended):
x = input()
y = x.split(' ')
count = 0
i = 0
while(i < len(y) - 1):
if(int(y[i]) * 2 == int(y[i+1])):
count += 1
i += 1
print(count)
Before I continue, here are a few tips and notes: (some of them will only make sense after)
I assume the 14 in your example is a typo
I didn't put the code in a function because it's not needed, but you can change it easily.
In your code, you are passing L as a parameter to the countDouble() function, but you don't use it. if you don't need a parameter don't pass it.
when splitting the input, the values of the list are still strings. so you have to invert them to integers (for instance, you can do that with the int() 'function') before comparing their values - otherwise multiplying by 2 will just repeat the string. for example: '13'*2 is the string '1313'
I don't know why you why you added y[0] to itself in line 9, but based on the code that comes after this would yield incorrect results, you don't need to change the elements in order to get their value multiplied by 2.
notice that in the else block, nothing has changed. adding 0 to the count doesn't change it. so you can remove the else block entirely
While it's possible to solve the problem in recursion, there's something else designed for these kind of problems: loops.
The problem is essentially repeating a simple check for every element of a list.
This is how I would arrive to a solution
so we want to run the following 'code':
if(y[0]*2 == y[1]):
count += 1
if(y[1]*2 == y[2]):
count += 1
if(y[2]*2 == y[3]):
count += 1
...
of course the computer doesn't understand what "..." means, but it gives us an idea to the pattern in the code. now we can do the following:
divide the extended 'code' into similar sections.
identify the variables in the pattern - the values that change between sections
find the starting values of all variables
find a pattern in the changes of each variable
find a breaking point, a condition on one of the variables that tells us we have reached the last repeating section.
here are the steps in this specific problem:
the sections are the if statements
the variables are the indexes of the elements in y we compare
the first index starts at 0 and the second at 1
both indexes increase by one after each if-statement
when the second index is bigger then the last index of y then we already checked all the elements and we can stop
so all is left is to set the needed variables, have a while loop with the breaking condition we found, and in the while loop have the general case of the repeating sections and then the changing of the variables.
so:
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = 0
# setting the starting values of the variables
index1 = 0
index2 = 1
# creating a loop with the breaking condition
while(index2 < len(y)):
# the general case of the repeated code:
if(int(y[index1]) * 2 == int(y[index2])):
count += 1
# changing the variables for the next loop
index1 += 1
index2 += 1
print(count)
We see that the index2 is just index1 + 1 at all time. so we can replace it like that:
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = 0
index1 = 0
while(index1 + 1 < len(y)):
if(int(y[index1]) * 2 == int(y[index1 + 1])):
count += 1
index1 += 1
print(count)
Note: You can use a for loop similarly to the while loop
So in summary, you can use recursion to solve the problem, but the recursion would just be imitating the process of a loop:
in each call, the breaking condition will be checked, the repeated code would run and the variables/parameters would change.
Hope you find this answer useful :)
Final edit: OP edited his example so my other code didnt apply
Some good questions people are asking, but in the spirit of helping, here's a recursive function that returns the count of all doubles.
def get_doubles_count_with_recursion(a_list, count, previous=None):
while a_list:
try:
first = previous if previous else a_list.pop(0)
next_item = a_list.pop(0)
except IndexError:
return count
if next_item / 2 == first:
count += 1
return get_doubles_count_with_recursion(a_list, count, next_item)
return count
a_list = [1, 3, 5, 10, 11, 14, 28, 56, 88, 116, 232, 464, 500]
doubles = get_doubles_count_with_recursion(a_list, 0)
print(doubles == 5)
Probably could clean it up a bit, but it's a lot easier to read than the other guy's ;)
If I'm reading your question right, you want a count of all pairs where the 2nd item is double the first. (and the 14 in the first list is a typo). In which case a simple function like this should do the job:
#a = [2,4,8,16,32]
a = [-5, -10, 0, 16, 32]
count = 0
for i, x in enumerate(a):
# Stop before the list overflows
if i < len(a) - 1:
# If the next element is double the current one, increment the counter
if a[i+1] == x * 2:
count = count + 1
else:
break
print(count)

Is there any way I can use less memory and make the run time shorter?

heres the prompt:
construct a numeral triangle according to the following rules:
the first row contains a starting number
each of the new rows has one more number than prev
each number is a specified larger amount than the last
before adding to the "triangle", make sure all the characters of multi digit numbers are added together to form a one digit number
return the sum of the last row in the "triangle"
heres my answer: the first function takes care of the fourth requirement, it adds the digits of a number up until there is only one digit. example: 123 = 1+2+3 = 6. The second function takes in s (starting value), d (increments), and r (number of rows). It creates boxnum, which are the total number of boxes in the triangle and how many times I must add the increment to the previous value. if r = 99,999, the entire code will loop that many times and it will exceed the time limit which is my problem. i also have a problem with storage, because each value is being appended to the list when in reality i only need the last row. I'm not sure how to re-write and cut down my code.
def multidigit(x):
numsum = 0
if x < 9:
return(x)
else:
for number in str(x):
numsum += int(number)
if numsum > 9:
return(multidigit(numsum))
else:
return(numsum)
def sumOfLastRow(s, d, r):
rowslist = []
rowslist.append(multidigit(s))
incrementnum = s
boxnum = 0
for i in range(r+1):
boxnum = boxnum + i
for i in range(boxnum-1):
incrementnum = incrementnum + d
if incrementnum > 9:
incrementnum = multidigit(incrementnum)
rowslist.append(incrementnum)
splitlist = rowslist[-r:]
rowslist.clear()
total = 0
for i in range(len(splitlist)):
total = total + splitlist[i]
return(total)
if x < 9:
return(x)
That doesn't look right.
Probably you started out with an infinite loop bug on the x == 9 case,
and then tacked on the final else to paper over it.
I bet you wanted
if x <= 9:
return int(x)
Much simpler to
return sum(map(int, str(x)))
You could use a similar idiom when computing total.
for i in range(r+1):
boxnum = boxnum + i
There's no need to loop, here, as a quadratic closed form solution is available.
https://dev.to/alisabaj/the-gauss-sum-and-solving-for-the-missing-number-996

Why is this code not running fully? It doesn't run line 53

I made myself an exercise with python since I am new. I wanted to make a rever LMC calculator ( Least common multiple ) but for some reason, something as simple as a print in a loop doesn't seem o work for me. I would appreciate some help since I am stuck on this weird issue for 20 minutes now. Here is the code:
import random
import sys
def print_list():
count_4_print = 0
while count_4_print < len(values):
print(values[count_4_print])
count_4_print += 1
def lcm(x, y):
if x > y:
greater = x
else:
greater = y
while True:
if (greater % x == 0) and (greater % y == 0):
lcm1 = greater
break
greater += 1
return lcm1
def guess(index, first_guess, second_guess):
num = 1
while lcm(first_guess, second_guess) != values[num - 1]:
first_guess = random.randrange(1, 1000000)
second_guess = random.randrange(1, 1000000)
num += 1
num = 1
if lcm(first_guess, second_guess) == values[num - 1]:
return first_guess, second_guess
num += 1
lineN = int(input())
values = []
count_4_add = 0
count_4_guess = 0
for x in range(lineN):
values.append(int(input()))
count_4_add += 1
if count_4_add >= lineN:
break
print_list()
for x in range(lineN + 1):
first, second = guess(count_4_guess, 1, 1)
count_4_guess += 1
print(first + second)
# this ^^^ doesn't work for some reason
Line 57 is in the while loop with count_4_guess. Right above this text, it says print(first_guess + second_guess)
Edit: The code is supposed to take in an int x and then prompt for x values. The outputs are the inputs without x and LMC(output1, output2) where the "LMC" is one of the values. This is done for each of the values, x times. What it actually does is just the first part. It takes the x and prompts for x outputs and then prints them but doesn't process the data (or it just doesn't print it)
Note: From looking at your comments and edits it seems that you are lacking some basic knowledge and/or understanding of things. I strongly encourage you to study more programming, computer science and python before attempting to create entire programs like this.
It is tough to answer your question properly since many aspects are unclear, so I will update my answer to reflect any relevant changes in your post.
Now, onto my answer. First, I will go over some of your code and attempt to give feedback on what could improved. Then, I will present two ways to compute the least common multiple (LCM) in python.
Code review
Code:
def print_list():
count_4_print = 0
while count_4_print < len(values):
print(values[count_4_print])
count_4_print += 1
Notes:
Where are the parameters? It was already mentioned in a few comments, but the importance of this cannot be stressed enough! (see the note at the beginning of my comment)
It appears that you are trying to print each element of a list on a new line. You can do that with print(*my_list, sep='\n').
That while loop is not how you should iterate over the elements of a list. Instead, use a for loop: for element in (my_list):.
Code:
def lcm(x, y):
if x > y:
greater = x
else:
greater = y
while True:
if (greater % x == 0) and (greater % y == 0):
lcm1 = greater
break
greater += 1
return lcm1
Notes:
This is not a correct algorithm for the LCM, since it crashes when both numbers are 0.
The comparison of a and b can be replaced with greater = max(x, y).
See the solution I posted below for a different way of writing this same algorithm.
Code:
def guess(index, first_guess, second_guess):
num = 1
while lcm(first_guess, second_guess) != values[num - 1]:
first_guess = random.randrange(1, 1000000)
second_guess = random.randrange(1, 1000000)
num += 1
num = 1
if lcm(first_guess, second_guess) == values[num - 1]:
return first_guess, second_guess
num += 1
Notes:
The line num += 1 comes immediately after return first_guess, second_guess, which means it is never executed. Somehow the mistakes cancel each other out since, as far as I can tell, it wouldn't do anything anyway if it were executed.
if lcm(first_guess, second_guess) == values[num - 1]: is completely redundant, since the while loop above checks the exact same condition.
In fact, not only is it redundant it is also fundamentally broken, as mentioned in this comment by user b_c.
Unfortunately I cannot say much more on this function since it is too difficult for me to understand its purpose.
Code:
lineN = int(input())
values = []
count_4_add = 0
count_4_guess = 0
for x in range(lineN):
values.append(int(input()))
count_4_add += 1
if count_4_add >= lineN:
break
print_list()
Notes:
As explained previously, print_list() should not be a thing.
lineN should be changed to line_n, or even better, something like num_in_vals.
count_4_add will always be equal to lineN at the end of your for loop.
Building on the previous point, the check if count_4_add >= lineN is useless.
In conclusion, count_4_add and count_4_guess are completely unnecessary and detrimental to the program.
The for loop produces values in the variable x which is never used. You can replace an unused variable with _: for _ in range(10):.
Since your input code is simple you could probably get away with something like in_vals = [int(input(f'Enter value number {i}: ')) for i in range(1, num_in_vals+1)]. Again, this depends on what it is you're actually trying to do.
LCM Implementations
According to the Wikipedia article referenced earlier, the best way to calculate the LCM is using the greatest common denominator.
import math
def lcm(a: int, b: int) -> int:
if a == b:
res = a
else:
res = abs(a * b) // math.gcd(a, b)
return res
This second method is one possible brute force solution, which is similar to how the one you are currently using should be written.
def lcm(a, b):
if a == b:
res = a
else:
max_mult = a * b
res = max_mult
great = max(a, b)
small = min(a, b)
for i in range(great, max_mult, great):
if i % small == 0:
res = i
break
return res
This final method works for any number of inputs.
import math
import functools
def lcm_simp(a: int, b: int) -> int:
if a == b:
res = a
else:
res = abs(a * b) // math.gcd(a, b)
return res
def lcm(*args: int) -> int:
return functools.reduce(lcm_simp, args)
Oof, that ended up being way longer than I expected. Anyway, let me know if anything is unclear, if I've made a mistake, or if you have any further questions! :)

Next Word in Lexicographic Order

Problem
There is a word given. We need to find the next word occurring in lexicographic order.For example, if word is lkjihfg then the next word would be lkjihgf.
This is a problem at Hackerrank that you can see here.
The problem for reference:
Complete the biggerIsGreater function in the editor below. It should
return the smallest lexicographically higher string possible from the
given string or no answer.
My effort
What i've tried was finding the maximum index(say indx) of word such that after it all the characters are non increasing.Then swapping the char at indx with the minimum char ahead that is greater than char at indx. Finally, reversing the string after indx.
Code
def biggerIsGreater(w):
ww = list(set(w))
indx = -1
l = [ord(ch)for ch in w]
for i in range(len(l)-1):
if l[i] < l[i+1]:
indx = i
else:
continue
if indx == -1:
return "no answer"
j = len(l) - 1
for x in range(j,indx,-1):
if l[x] > l[indx]:
l[x], l[indx] = l[indx], l[x]
break
l[indx+1 : ] = l[len(l) - 1 : indx : -1]
y = []
for z in l:
y.append(chr(z))
ans = ''.join(y)
return ans
The problem with this code is that it's not passing all the test cases because it's producing wrong results.
The good thing about your solution is that it has a good time complexity - O(n), where n is a size of the input string. That's why you don't have any timeout errors.
The problem with this code is, however is not all the test cases are validating.
That's so because you've missed one important case in your loop below:
for x in range(j,indx,-1):
if l[x] >= l[indx]:
l[x], l[indx] = l[indx], l[x]
break
Consider a case like 5 4 6 4. So, your indx is 2 and because of your condition l[x] >= l[indx] you will replace l[2] = 4 with l[0] = 4. This way, your next word in lexicographical order won't change and you'll get a wrong result 5 4 4 6 even though it must be 5 6 4 4.
So, if you make your condition stricter > and not >= because you actually need a LARGER character from the left then the solution will be working correctly.
Hence, just change your condition to > :
for x in range(j,indx,-1):
if l[x] > l[indx]: # fix the sign here
l[x], l[indx] = l[indx], l[x]
break
I tested your code with the fix and it passed all the tests.

Categories