So I'm trying to make a sudoku game and it's coming along fairly well except at the state I'm at the program gives me an error for every move I try to make. isRow checks if a move is possible on the row and so on and isPossible combines the 3 to check if a move is possible or not. Can anyone tell me what is wrong with my verifications?
board = list(range(81)) # Creates a board with 9*9 elements
board2 = board # Duplicates this board for later verfications
def showLine(start, end): # Prints each line of the sudoku puzzle
for i in range(start, end):
if i < end-1:
print(str(board[i]), '|', end =" ")
else:
print(str(board[i]))
def showGroup(start): # Prints each 9*3 group of regions (1/3 of the puzzle)
for i in range(3):
end = start + 9
showLine(start, end)
start += 9
if start != 81:
print('----------+-----------+-----------')
def show(): # Prints whole puzzle
for i in range(0, 55, 27):
showGroup(i)
rows = []
columns = []
groups = []
for i in range(0, 80, 9): # Cretes a list of rows
rows.append(board[i:i+9])
for i in range(9): # Creates a list of columns
columns.append(board[i::9])
temp = 0
for x in range(0, 61, 3): # Creates a list of groups (3*3 regions)
group = []
for i in range(3):
for j in range(3):
temp = x + 9*i + j
group.append(temp)
groups.append(group)
#Duplicating rows columns and groups for verifications
rows2 = rows
columns2 = columns
groups2 = groups
def isRow(cell, number): # Checking if an introduces number isn't repeating in the row
x = 0
for row in rows2:
if cell in row:
x = rows2.index(row)
if number in rows[x]:
return False
else:
return True
def isColumn(cell, number):): # Checking if an introduces number isn't repeating in the column
x = 0
for column in columns2:
if cell in column:
x = columns2.index(column)
if number in columns[x]:
return False
else:
return True
def isGroup(cell, number):): # Checking if an introduces number isn't repeating in the group
x = 0
for group in groups2:
if cell in group:
x = groups2.index(group)
if number in groups[x]:
return False
else:
return True
def isPossible(cell, number): # Combines the last 3 verifications
if isRow(cell, number) and isColumn(cell, number) and isGroup(cell, number):
return True
else:
return False
for i in board: # Fills the board with 0's to not interfere with the game
board[i] = 0
while True:
show()
selected_cell = int(input("Please select an available cell: "))
number = int(input("Please select a number for that cell: "))
if isPossible(selected_cell, number):
board[selected_cell] = number
else:
print("Error, please try again")
Related
I'm currently learning BackTracking algorithms with Python and the first question everyone typically starts with is NQueens. NQueens is where you take a board of size N x N and you have to determine where to place N queens, in such an order they are not attacked by any other queen.
Example:
N = 5
['Q', 0, 0, 0, 0]
[0, 0, 'Q', 0, 0]
[0, 0, 0, 0, 'Q']
[0, 'Q', 0, 0, 0]
[0, 0, 0, 'Q', 0]
Currently, my algorithm returns ALL Possible Solutions. How do I produce ONE outcome. For instance, when N = 8, there are 92 optimal outcomes, how do I just return One Outcome instead of printing 92 separate Outcomes.
#This is our main recursive function that will determine optimal outcome
def NQueens(row,Current,N):
#this tells us when to stop
if row == N:
print("\n")
return printBoard(Current)
for choice in range(0,N):
if isValid(row,choice,Current,N):
#Place Queen in appropriate spot
Current[row][choice] = "Q"
#Go to next row
NQueens(row+1,Current,N)
Current[row][choice] = 0
return "All Solutions Found"
#This function determines whether we can put a Queen in a certain orientation on the board
def isValid(row,col,Current,N):
#check whether current state of game has queen in row/column
for i in range(0,N):
#checks column/row and sees whether a queen exists already
if Current[row][i] == "Q" or Current[i][col] == "Q":
return False
# Check upper diagonal on right side
i = row-1
j = col + 1
#Do while row is greater than 0 and column is less than N
while i >= 0 and j < N:
if Current[i][j] == "Q":
return False
i -= 1
j += 1
# Check upper diagonal on left side
#Do while row is greater than 0 and column is greater than N
i = row-1
j = col - 1
while i >= 0 and j >= 0:
if Current[i][j] == "Q":
return False
i -= 1
j -= 1
#If we pass the diagonal/row/column tests, we can then determine this is a valid move
return True
###############################################################################################################
#These functions deal with board creation and printing them in a proper format
def generateBoard(N):
#generate board based on User Input N in Main()
Board = [[0 for i in range(0,N)] for j in range(0,N)]
return Board
def printBoard(arr):
#Loop through each row to print an organized board
for row in arr:
print(row)
def main():
#ask number from user
print("What sized board would you like?"
" Please input a number higher that 3: ")
#user input used to determine size of board
N = int(input())
#generate Board that will be used
Board = generateBoard(N)
#this is the current status of the board
printBoard(Board)
print("\n")
#Runs Algorithm
print(NQueens(0,Board,N))
if __name__ == "__main__":
main()
NQueens needs to communicate to its caller that a solution has been found; a simple return True will do if that's the case. I made the following changes to your code (your previous lines are commented):
def NQueens(row,Current,N):
#this tells us when to stop
if row == N:
print("\n")
#return printBoard(Current)
return True # found a solution, say so
for choice in range(0,N):
if isValid(row,choice,Current,N):
#Place Queen in appropriate spot
Current[row][choice] = "Q"
#Go to next row
# NQueens(row+1,Current,N)
if NQueens(row+1,Current,N): # recursive call found a solution, let's stop
return True
Current[row][choice] = 0
#return "All Solutions Found"
And in main():
# ...
#Runs Algorithm
#print(NQueens(0,Board,N))
if NQueens(0,Board,N):
printBoard(Board) # found a solution, print it
I have fixed your code to have well-perfoming:
I merge this code https://www.geeksforgeeks.org/n-queen-problem-backtracking-3/ and yours to get it.
count = 1
def printOut(arrayMap):
global count
print('{}: -'.format(count))
count += 1
for i in range(0, len(arrayMap)):
print(arrayMap[i])
# This is our main recursive function that will determine optimal outcome
def NQueens(currentRow, arrayMap, matrixSize):
# this tells us when to stop
if currentRow == matrixSize:
print()
printOut(arrayMap)
return True # found a solution, say so
res = False
for col in range(0, matrixSize):
if isValid(currentRow, col, arrayMap, matrixSize):
# Place Queen in appropriate spot
arrayMap[currentRow][col] = 0
# Go to next row
# NQueens(row+1,Current,N)
res = NQueens(currentRow + 1, arrayMap, matrixSize) or res # recursive call found a solution, let's stop
arrayMap[currentRow][col] = 1
# return "All Solutions Found"
return res
# This function determines whether we can put a Queen in a certain orientation on the board
def isValid(row, col, arrayMap, matrixSize):
# check whether current state of game has queen in row/column
for i in range(0, matrixSize):
# checks column/row and sees whether a queen exists already
if arrayMap[row][i] == 0 or arrayMap[i][col] == 0:
return False
# Check upper diagonal on right side
i = row - 1
j = col + 1
# Do while row is greater than 0 and column is less than N
while i >= 0 and j < matrixSize:
if arrayMap[i][j] == 0:
return False
i -= 1
j += 1
# Check upper diagonal on left side
# Do while row is greater than 0 and column is greater than N
i = row - 1
j = col - 1
while i >= 0 and j >= 0:
if arrayMap[i][j] == 0:
return False
i -= 1
j -= 1
# If we pass the diagonal/row/column tests, we can then determine this is a valid move
return True
###############################################################################################################
if __name__ == "__main__":
# ask number from user
print("What sized board would you like?")
N = int(input('Choose your size: '))
# generate Board that will be used
Board = [[1 for i in range(0, N)] for j in range(0, N)]
count = 0
NQueens(0, Board, N)
My code all work fine apart from the list at the very bottom "newList = [i + j for i, j in zip(numberString, products)]". I expected it to add all the elements within the two list without fault, sort of like this: [a9, b7, c5, d3, e1].
Instead i got this: "['[a', '[b', '9c', ',d', ' e']". Both lists are strings, so i'm not sure why they aren't concatenating properly.
# create an empty list for your products.
products = []
# Asking for the number of elements to be inputted.
n = int(input("Enter number of products you're buying : "))
# Some UI for the customer.
print("What are these products?")
# iterating until the range that has been chosen.
for i in range(0, n):
ele = input()
products.append(ele) # adding the element
def sort_numbers(number_list):
# sorts a list of valid numbers in descending numerical order
swaps = True
loopcount = len(number_list) - 1
while loopcount > 0 and swaps:
swaps = False
for i in range(loopcount):
if number_list[i] < number_list[i + 1]:
number_list[i], number_list[i + 1] = number_list[i + 1], number_list[i]
swaps = True
loopcount = loopcount - 1
def input_numbers(number_list):
# inputs shopping items and costs and stores them in two lists
user_input = input('Input a number of type Q to quit ')
while user_input.upper() != 'Q':
valid_number = False
while valid_number == False:
# use an exception handler to cover non-numeric input
try:
number_list.append(int(user_input))
valid_number = True
except ValueError:
print('Please enter a valid number')
user_input = input('Input a number or type Q to quit ')
user_input = input('input a number or type Q to quit ')
def totalise_numbers(number_list):
# sums us the list of numbers
total = 0
for i in range(len(number_list)):
total = total + number_list[i]
print('The total of the numbers is ', total)
print('The total of the numbers minus the smallest number is ', total - number_list[0])
# initialise the list
numbers = []
# call the function to create the list of numbers
input_numbers(numbers)
# sort the list in ascending order
sort_numbers(numbers)
# Totalise the numbers
totalise_numbers(numbers)
numberString = str([numbers])
# print the list of numbers
newList = [i + j for i, j in zip(numberString, products)]
print(newList)
print(numbers)
Replace the few bottom lines with this code.
numberString = numbers
# print the list of numbers
newList = [str(i) + j for i, j in zip(numberString, products)]
print(newList)
print(numbers)
A friend recently asked me to code an algorithm that takes n 'people' and produces an n-1 by n/2 grid, where every possible pair occurs once and in each n/2 section nobody is allowed to occur twice. (i.e. person1 matched with person 2 and person1 matched with person3 is invalid).
If that doesn't make sense imagine this: for 100 people create 99 rounds of meetings where everyone meets someone new in each round but nobody has more than one meeting in a round. This way 50 unique meetings occur each round, for 99 rounds, totalling 4950 unique meetings.
I have coded this in python using recursive backtracking (not sure if this is the best method. This problem reminds me of sudoku and this is a popular method of solving sudoku) This takes a stupid amount of time even for smallish numbers (50 for example). Is there a faster method of coding this or are there augmentations I can add to make it run faster?
Code is here: https://pastebin.com/iyr2wdkz
import random
from itertools import combinations
import time as t
import sys
sys.setrecursionlimit(15000)
def isPrime(num):
"""Checks num for primality. Returns bool."""
if num == 2:
return True
elif num < 2 or not num % 2: # even numbers > 2 not prime
return False
# factor can be no larger than the square root of num
for i in range(3, int(num ** .5 + 1), 2):
if not num % i: return False
return True
def generatePrimes(n):
"""Returns a list of prime numbers with length n"""
primes = [2,]
noOfPrimes = 1 # cache length of primes for speed
testNum = 3 # number to test for primality
while noOfPrimes < n:
if isPrime(testNum):
primes.append(testNum)
noOfPrimes += 1
testNum += 2
return primes
class Person:
def __init__(self, name, ID):
self.name = name
self.primeID = ID
def __eq__(self, other):
return self.primeID == other
def __repr__(self):
return '%d' % (self.name)
class Schedule:
def __init__(self, numberofpeople):
self.x = 0 #current x pos
self.y = 0 #current y pos
self.fill = 0 #number of slots filled
self.board = [] #get initialized to an n-1 x n/2 grid to hold links
self.failed = [] #same as board but holds a list of failed links in each cell
self.uniqueLinks = [] #list of unique links, a link is the product of two primes
self.availableLinks = [] #links not yet placed in the grid
self.personList = [] #list of Person. A person is a name and a unique prime number
self.primeList = generatePrimes(numberofpeople) #list of the first n prime numbers
random.shuffle(self.primeList)
#initializes the empty lists
for i in range(numberofpeople):
self.personList.append(Person(i, self.primeList[i]))
self.uniqueLinks = list(map(lambda x: x[0] * x[1], combinations(self.primeList, 2)))
for i in self.uniqueLinks:
self.availableLinks.append(i)
tmp = len(self.uniqueLinks)
for i in range(tmp // (numberofpeople // 2)):
self.board.append(list())
self.failed.append(list())
for i in range(len(self.board)):
for j in range(numberofpeople//2):
self.board[i].append(None)
self.failed[i].append(list())
#checks if the candidate is valid in current position
def isValid(self, candidate):
factor1, factor2 = self.getFactor(candidate)
for i in self.board[self.x]:
if not i:
return True
if ((i % factor1) == 0) or ((i % factor2) == 0):
return False
return True
#moves to the next non-None value, return True if successful
def nextpos(self):
for i in range(len(self.board)):
for j in range(len(self.board[0])):
if not self.board[i][j]:
self.x = i
self.y = j
return True
return False
#sets the last non-None value to None and adds that value to availableLinks and the failed tracker
def prevpos(self):
for i in range(len(self.board)-1, -1, -1):
for j in range(len(self.board[0])-1, -1, -1):
if self.board[i][j]:
self.x = i
self.y = j
tmp = self.board[self.x][self.y]
self.availableLinks.append(tmp)
self.board[i][j] = None
self.failed[i][j].append(tmp)
self.fill -= 1
random.shuffle(self.availableLinks)
return True
#returns the prime factors of num
def getFactor(self, num):
for i in self.primeList:
if num % i == 0:
return i, num/i
#recursive backtracking solving algorithm
def solve(self):
print('%d links placed, %d remaining, pos is %d, %d' % (self.fill, len(self.availableLinks), self.x, self.y))
if not self.nextpos():
return True
for i in self.availableLinks:
if self.isValid(i): and self.checkFail(i):
self.fill += 1
self.board[self.x][self.y] = i
self.availableLinks.remove(i)
if self.solve():
return True
else:
self.prevpos()
return False
#replaces prime products with formatted names of people in the board
def decompose(self):
for i in range(len(self.board)):
for j in range(len(self.board[0])):
num1, num2 = self.getFactor(self.board[i][j])
for k in self.personList:
if k == num1:
person1 = str(k)
if k == num2:
person2 = str(k)
self.board[i][j] = person1 + '<-->' + person2
# checks if num has already been tried at current pos, returns false if is has.
def checkFail(self, num):
if num in self.failed[self.x][self.y]:
return False
else:
return True
# verifies that the board has no duplicate values
def verify(self):
visited = []
for i in self.board:
for j in i:
if j in visited:
print('Verification failed %s occurs twice'% j)
return False
visited.append(j)
print('Successfully verified')
return True
s =Schedule(50)
s.solve()
s.verify()
s.decompose()
print(s.board)
What an impressive amount of code!
Here is a solution in scala. I just use Ints, which you may map to Person.ID:
def greetAsMad (persons: List [Int]) : List [(Int, Int)] =
if (persons.size < 2) Nil else
persons.tail.map (p=> (persons.head, p)) ::: greetAsMad (persons.tail)
For 100 persons, it returns immediately (< 200ms).
To be prepared for a larger amount of persons, I would transform it into a tail-recursive function.
The idea is, that person 1 greets everybody and leaves the room. Then person 2 greets everybody and leaves too. In the end person 99 greets person 100 and both leave the room.
Then they start eating and drinking.
Here is a non recursive approach:
for (i <- 1 to 99;
j <- i + 1 to 100) yield (i, j)
Seems you need round-robin tournament algorithm.
In short: make two-rows table, fix the first entry of the first row, and shift all other entries in cyclic manner (n-1 times). At every round pairs are formed by top and bottom entries in the same columns
0 1
2 3
----- pairs 0-2, 1-3
0 2
3 1
---- pairs 0-3, 2-1
0 3
1 2
----- pairs 0-1, 3-2
so i am a newbie so be easy on me i was just trying to solve a problem in hackerrank.com
in which i must get the max number of continous 1's in a binary representation of number and i made it but it is not working Heres the Code
the updated code is below
import statistics
# Get the input using the variable Getinput
Getinput = int(input())
# def a function names 1 seq
def one_seq(n):
main = []
# get the binary of the number taken into input
# convert the binary number to a string
number = "{0:b}".format(n)
# i = 0
i = 0
# sub_main =[]
sub_main = []
#a while loop
while i != len(number)-1:
#if number[i] == "1":
if number[i] == "1":
sub_main.append(number[i])
#else definately 0 so append sub_main to main and sub_main = []
else:
main.append(sub_main)
sub_main = []
i+=1
# greatest 1 = len(x) for element in main
#greatest_one = [len(element) for element in main ]
greatest_one = [len(element) for element in main]
#return greatest_one
return max(greatest_one)
print(len(one_seq(Getinput)))
import statistics
# Get the input using the variable Getinput
# def a function names 1 seq
def one_seq(n):
main = []
# get the binary of the number taken into input
# convert the binary number to a string
number = str("{0:b}".format(n))
# i = 0
i = 0
# sub_main =[]
sub_main = []
#a while loop set to True
while i != len(number):
#if number[i] == 1:
if number[i] == 1:
sub_main.append(number[i])
#else definately 0 so append sub_main to main and sub_main = []
else:
main.append(sub_main)
sub_main = []
continue
i+=1
# greatest 1 = len(x) for element in main
greatest_one = [len(element) for element in main ]
return statistics.mode(greatest_one)
one_seq(2)
You're close. I'll annotate your mistakes to point you in the right direction,
import statistics
def one_seq(n):
main = []
number = str("{0:b}".format(n))
i = 0
sub_main = []
while i != len(number):
if number[i] == 1: # you want to check against the string '1' not the number 1
sub_main.append(number[i])
else:
main.append(sub_main)
sub_main = []
continue # this will skip the i+=1 and cause an infinite loop
i+=1
greatest_one = [len(element) for element in main ]
return statistics.mode(greatest_one) # There's no reason to use mode here.
# You want the greatest element in the list
# Not the most common.
Remember if you get stuck you can always insert prints everywhere.
Ints and strings
number = 11 # binary 1100101
binary = str("{0:b}".format(number))
print(binary[0] == 1) # prints False
print(binary[0] == '1') # prints True
The important thing to keep in mind is that the variable binary is a str. In Python a string is written 'hello' or '0', while an int is written 0 or 1 or 3562. When an int is compared to a string using == it will always return False.
The meaning of continue
while True:
print('This be printed over and over')
continue
print('This will never be printed')
Continue skips the rest of an iteration of a loop.
Finding the max of a list
mylist = [8, 2, 4, 68, 7]
largest = max(mylist)
print(largest) # prints 68
The solution
def one_seq(n):
main = []
number = str("{0:b}".format(n))
print(number)
i = 0
sub_main = []
while i != len(number):
if number[i] == '1': # Changed 1 to '1'
sub_main.append(number[i])
else:
main.append(sub_main)
sub_main = []
# Removed continue
i+=1
main.append(sub_main) # This is something I missed earlier
# this fixes an issue with numbers
# ending with 1s.
greatest_one = [len(element) for element in main ]
return max(greatest_one) # Used max instead of mode
Simplified
I would probably write it like this
def one_seq(n):
current = 0
longest = 0
for digit in '{0:b}'.format(n):
if digit == '1':
current += 1
else:
longest = max(current, longest)
current = 0
longest = max(current, longest)
return longest
I'm currently having an issue with my code. The program works properly but for some reason when I enter all positive numbers I receive an error for the last function. The last function is removing all the negative numbers from the list.
i=0
numList = []
x = int(input("Please enter number from -9999 to end:"))
while x > -9999:
i = i + 1
numList.insert(i,x)
x = int(input("Please enter number from -9999 to end:"))
if x == -9999:
print("The list of numbers entered:",(numList))
newList = numList[:]
secList = numList[:]
def posNumAvg(newList):
for e in newList[:]:
if e < 0:
newList.remove(e)
def negNumAvg(secList):
for y in secList[:]:
if y > 0:
secList.remove(y)
posNumAvg(newList)
negNumAvg(secList)
mydict = {'AvgPositive':(sum(newList)//len(newList)),'AvgNonPos': (sum(secList)//len(secList)),'AvgAllNum':(sum(numList)//len(numList))}
print("The dictionary with averages is:",mydict)
You are trying to compute the average of an empty list, which is not defined (specifically, the list's length is zero so you end up dividing by zero).
You need to decide what you want to do in that case and handle it specifically.
As an aside, you can rewrite
for e in newList[:]:
if e < 0:
newList.remove(e)
as
newList = [e for e in newList if e >= 0]
NOte: Never modify the list when you iterating over it. Let me make some changes to your code
numList = []
while True:
x = int(input("Please enter number from -9999 to end:")
if x == -9999:
print("The list of numbers entered:",(numList))
break
# you don't need i here, used append to insert element at last of list
# insert is used to insert a element at specific position
numList.append(x)
def posNumAvg(gotList):
list_negative = [] # will contain negative number
for e in gotList:
if e < 0:
list_negative.append(e)
return list_negative
def negNumAvg(gotList):
list_positive = [] # will contain positive number
for y in gotList:
if y >= 0:
list_positive.append(y)
return list_positive
list_positive = posNumAvg(numList)
list_negative = negNumAvg(numList)
mydict = {'AvgPositive':(sum(list_positive)//len(list_positive)),'AvgNonPos': (sum(list_negative)//len(list_negative)),'AvgAllNum':(sum(numList)//len(numList))}
print("The dictionary with averages is:",mydict)
you can get positive and negative number from one function: see this code
def neg_poss(gotList):
list_positive = [] # will contain positive number
list_negative = [] # will contain negative number
for y in gotList:
if y >= 0:
list_positive.append(y)
else:list_negative.append(y)
return list_positive,list_negative
list_positive,list_negative = neg_post(numList)