Add threads to a Sudoku checker - python

I have just created a simple function in Python which checks whether or not a Sudoku board (input is given as a list) is valid or not. The way I did it is pretty straight forward:
check if the sudoku board is 9x9
check that each number appears only once per row
check that each number appears only once per column
check that each number appears exactly once per 3x3 grid
Now, once I started this, I wanted to take advantage and learn a bit about Python threads. I read the docs, and also some awesome general multithreading related posts here on SO, but I just couldn't think of a way of implementing them in my checker.
Now, the way I'd like the threads works (as I thought) is one thread to check that each column contains 1-9 digits, another one to check the lines for the same thing, and another nine threads to check each 3x3 sub-grid. Could you guys please tell me (eventually with some explanations) how I could achieve this ? Thanks

So to give some general pointers on how to achieve this, without taking away any challenge. Lets start by import Threading:
import threading
Which will let us use thread objects! Also, in order to know if the Sudoku grid will be valid after the fact, we need a variable to store the True/False condition in. You can either go for a single variable, and use Thread Locks to ensure no other threads access it at the same time, or go with three separate. For simplicity, I'll use three separate variables in this example
LinesValid = False
ColumnsValid = False
GridsValid = False
Then, since threads require a function or another callable to run as their target, and you desire a thread for columns, rows and for each 3x3 grid, we need three functions for each thread. However, since there are 9 columns, 9 rows and also 9 grids I believe it would be a lot better to just do a single thread for the grids as well, but for the purpose of the exercise I suppose it is fine to do one for each.
def CheckLines():
# Line Checking Code
def CheckColumns():
# ColumnCheckingCode
def CheckGrid(UpperLeft, BottomRight):
# GridCheckingCode
Anyway, here we define our three functions, with their appropriate line checking code. Like the lines would check the X axis, and the Columns the Y axis, but the idea is to split it up. For the CheckGrid you would need to specify corners if you want it to have a thread for each tile, or if you decide on a single thread you would just define it as:
def CheckGrid():
# GridCheckingCode
After that we need to make our Threads:
LineThread = threading.Thread(target=CheckLines)
ColumnThread = threading.Thread(target=CheckLines)
GridThread = threading.Thread(target=CheckLines, args=([0, 0], [2, 2]))
You can ignore the arguments from the GridThread if you do not need the grids. Otherwise you need to specify corners, and find a way to loop through the specified tiles.
After that it is a matter of starting the threads, and joining them with the main thread, before showing the data to the user:
LineThread.start()
ColumnThread.start()
GridThread.start()
LineThread.join()
ColumnThread.join()
GridThread.join()
if sum(LinesValid, ColumnsValid, GridsValid) == 3:
print("The grid is valid!")
else:
print("The grid is invalid!")
Here we check if all our Bools are True: ( 1 + 1 + 1 ) == 3 if they are, and print data to the user based on this. These bools would be set to True/False within their respective Check** functions!
If you desire some more direct solutions, rather than a general direction with explanations, please let me know and I'll throw something together! The final piece of code looks something like this:
import threading
def CheckLines(self):
# Line Checking Code
def CheckColumns(self):
# ColumnCheckingCode
def CheckGrid(self, UpperLeft, BottomRight):
# GridCheckingCode
LinesValid = False
ColumnsValid = False
GridsValid = False
LineThread = threading.Thread(target=CheckLines)
ColumnThread = threading.Thread(target=CheckLines)
GridThread = threading.Thread(target=CheckLines, args=([0, 0], [2, 2]))
LineThread.start()
ColumnThread.start()
GridThread.start()
LineThread.join()
ColumnThread.join()
GridThread.join()
if sum(LinesValid, ColumnsValid, GridsValid) == 3:
print("The grid is valid!")
else:
print("The grid is invalid!")

Related

Double ```for``` loop

I'm trying to make a nesting for loop to calculate points for my cribbage game. Right now I'm trying to figure out a method for counting all the '15's in the players hand. The way I currently have the system set up makes it so if 'dT' is in the hand, the card art for the ten of diamonds will print.
What I currently have (that is related to this question) is
hand = [] # this is filled by the rest of the program
handCombos = []
def count15s():
for _ in range(6):
possiblePairs = {'T5','J5','Q5','K5','78','96','5T','5J','5Q','5K','87','69'}
first = hand[0][1]
second = hand[2][1]
combo = ''.join(first+second)
if(combo in possiblePairs):
print('ham') # placeholder so the program can run without an error
print(combo)
This works for what it is supposed to--if the second part of the first term + the second part of the third term is in the list of possible pairs, then it prints 'ham' to the console. The problem with this, however, is that 1) It prints 'ham' 6 times, and 2) It actually does what it's supposed to.
I'm looking for a way that I can nest a for loop inside another one so it can scan every combination of '15's in the hand, then that specific combination to the handCombos array so that it can't be used again. I know that I need a for loop somewhere but the way I'm thinking of doing it would end up with a triple loop and I don't think that this is the best way to do it.

Is it possible to loop through a list of functions stored in a tuple?

Basically, I am creating a game: Connect 4. I want the AI to check both horizontally and vertically if the user is about to win every time a move is made. The reality is, it should implement only one check at a time because you can't make 2 moves at once anyway.
So, I have created 2 check functions. One for horizontal checking and one for vertical checking. i.e:
Let's assume player counter is 'X' and AI counter is 'O':
def horizonal_check():
if 'XXX'= True:
AI='XXXO'
The if statement in my actual game is more complicated that this but in essence, this is what it checks for then allows the AI to place its own counter in the appropriate place and stops me from winning.
def vertical_check():
if 'XXX' = True:
AI = 'XXXO'
This implements the same strategy as the function above but the only difference is, it checks for the vertical combination of 3 counters in a row instead of the horizontal combination.
So what I really want to do is store this 2 check functions in a tuple then use a for loop to loop through each one. This ensures only one check runs at a time. Here is my for loop:
Checks = (horizontal_check(), vertical_check()) # Checks stored in a tuple
for c in Checks:
return c
I want this for loop to loop through each individual check in the tuple one at a time. But it doesn't seem to work. The AI does nothing
You are currently creating a tuple containing the return values for your two function calls, None and None respectively, not the functions themselves.
Add the functions:
Checks = (horizontal_check, vertical_check) # Checks stored in a tuple
and then call them:
for c in Checks:
c()
Also, I am suspecting this is a trivialized example, but still:
Your function names don't match.
'XXX' = True isn't allowed (at least in an if), should be 'XXX' == True.
return in a for loop: it's a no-no.
its hard to tell but i guess you want this
Checks = (horizontal_check, vertical_check) # do not call the function here...
return any(c() for c in Checks) #call it as you loop through ...

Python program for rearranging an array swapping 2 at a time doesn't work, could someone help me?

This is the code I've written for a Python program (please keep in mind that I learnt Python from the Internet a couple of days ago). It is supposed to rearrange a inputted list (say, [3,2,4,1,5]), into, in the example case, [1,2,3,4,5].
For some reason, it's not working, and I can't figure the reason out. I've tried many different ways to do it, but none is working.
In this case, the program returns the same value as the original one.
Here's the code:
#General purpose string solver (by 2swapping + sune combos)
def solvepermutation():
#Setup
global pos
pos = raw_input('Ingrese permutacion.\n')
orientation = raw_input('Ingrese orientacion.\n')
#Generating solved position
solved=[]
for i in range(len(pos)):
solved.append(int(i+1))
#Solving pos
solvepos()
#Printing pos solved
print(pos)
#Function which solves pos
def solvepos():
global pos
for z in range(len(pos)-1):
for q in range(len(pos)):
if pos[z] == q+1:
pos[z],pos[q]=pos[q],pos[z]
continue
else:
continue
solvepos() operates on the global pos, but that's a string - when you do if pos[z] == q+1:, q+1 is an integer (one of the values from the range), but pos[z] is a string (one of the characters of the input). These will never compare equal, so no swap occurs.
There are many things that are wrong with this code, starting with the fact that sort is built in and it does no good to re-implement it. You also don't do anything with the solved list or orientation input; and you should be using parameters and return values instead of trying to communicate through global variables. But most importantly, don't iterate like that.

Python - 2 Questions: Editing a variable in a function and changing the order of if else statements internally/during runtime

First of all, I should explain what I'm trying to do first.
I'm creating a dungeon crawler-like game, and I'm trying to program the movement of computer characters/monsters in the map. The map is basically a Cartesian coordinate grid.
The locations of characters are represented by tuples of the x and y values, (x,y).
The game works by turns, and in a turn a character can only move up, down, left or right 1 space. I'm creating a very simple movement system where the character will simply make decisions to move on a turn by turn basis. Essentially a 'forgetful' movement system.
A basic flow chart of what I'm intending to do:
Find direction towards destination
Make a priority list of movements to be done using the direction eg.('r','u','d','l') means it would try to move right first, then up, then down, then left.
Try each of the possibilities following the priority order. If the first movement fails (blocked by obstacle etc.), then it would successively try the movements until the first one that is successful, then it would stop.
At step 3, the way I'm trying to do it is like this:
def move(direction,location):
try:
-snip- # Tries to move, raises the exception Movementerror if cannot move in the direction
return 1 # Indicates movement successful
except Movementerror:
return 0 # Indicates movement unsuccessful (thus character has not moved yet)
prioritylist = ('r','u','d','l')
if move('r',location): pass
elif move('u',location): pass
elif move('d',location): pass
elif move('l',location): pass
else: pass
In the if/else block, the program would try the first movement on the priority on the priority list. At the move function, the character would try to move. If the character is not blocked and does move, it returns 1, leading to the pass where it would stop. If the character is blocked, it returns 0, then it tries the next movement.
However, this results in 2 problems:
1.How do I edit a variable passed into a function inside the function itself, while returning if the edit is successful?
I have been told that you can't edit a variable inside a function as it won't really change the value of the variable, it just makes the variable inside the function refer to something else while the original variable remain unchanged. So, the solution is to return the value and then assign the variable to the returned value. However, I want it to return another value indicating if this edit is successful, so I want to edit this variable inside the function itself. How do I do so?
2.How do I change the order of the if/else statements to follow the order of the priority list? It needs to be able to change during runtime as the priority list can change resulting in a different order of movement to try.
Re 2., I would change your relatively-big if/elif tree to a simple loop:
prioritylist = ('r','u','d','l')
for direction in prioritylist:
if move(direction, location): break
less repetitious, easier to extend in the future if you want to allow diagonal steps or whatever -- and automatically "follows the priority list" in whatever order it's in, without any need to change your code itself.
Re 1., you can return multiple values from a function:
def move(direction,location):
try:
-snip-
return True, newlocation
except Movementerror:
return False, location
and you would then change the above loop to, e.g.:
prioritylist = ('r','u','d','l')
for direction in prioritylist:
success, newlocation = move(direction, location)
if success: break
else:
newlocation = location
using the else branch of the for, which executes if no break happens in the for, to deal with the case in which no attempt produced a success.
You can use a for-loop, and break out of the loop at the first successful choice:
for option in prioritylist:
if move(option,location): # succeeded
break
You should also return True or False, instead of a 1 or 0, as it makes the intention clearer.
Also, I should add that the statement about not editing a parameter is not entirely true... you cannot edit the parameter, itself, but you can edit the contents of that parameter assuming it is a mutable object. Tuples, which you are using, are immutable and so cannot be modified, but lists can be modified:
positions = ['N','S','E','W']
def mutate_list(p):
p.reverse()
print positions # prints ['N', 'S', 'E', 'W']
mutate_list(positions)
print positions # prints ['w', 'E', 'S', 'N']

Random list with rules

I'm trying to create a list of tasks that I've read from some text files and put them into lists. I want to create a master list of what I'm going to do through the day however I've got a few rules for this.
One list has separate daily tasks that don't depend on the order they are completed. I call this list 'daily'. I've got another list of tasks for my projects, but these do depend on the order completed. This list is called 'projects'. I have a third list of things that must be done at the end of the day. I call it 'endofday'.
So here are the basic rules.
A list of randomized tasks where daily tasks can be performed in any order, where project tasks may be randomly inserted into the main list at any position but must stay in their original order relative to each other, and end of day tasks appended to the main list.
I understand how to get a random number from random.randint(), appending to lists, reading files and all that......but the logic is giving me a case of 'hurty brain'. Anyone want to take a crack at this?
EDIT:
Ok I solved it on my own, but at least asking the question got me to picture it in my head. Here's what I did.
random.shuffle(daily)
while projects:
daily.insert(random.randint(0,len(daily)), projects.pop(0))
random.shuffle(endofday)
daily.extend(endofday)
for x in daily: print x
Thanks for the answers, I'll give ya guys some kudos anyways!
EDIT AGAIN:
Crap I just realized that's not the right answer lol
LAST EDIT I SWEAR:
position = []
random.shuffle(daily)
for x in range(len(projects)):
position.append(random.randint(0,len(daily)+x))
position.sort()
while projects:
daily.insert(position.pop(0), projects.pop(0))
random.shuffle(endofday)
daily.extend(endofday)
for x in daily: print x
I LIED:
I just thought about what happens when position has duplicate values and lo and behold my first test returned 1,3,2,4 for my projects. I'm going to suck it up and use the answerer's solution lol
OR NOT:
position = []
random.shuffle(daily)
for x in range(len(projects)):
while 1:
pos = random.randint(0,len(daily)+x)
if pos not in position: break
position.append(pos)
position.sort()
while projects:
daily.insert(position.pop(0), projects.pop(0))
random.shuffle(endofday)
daily.extend(endofday)
for x in daily: print x
First, copy and shuffle daily to initialize master:
master = list(daily)
random.shuffle(master)
then (the interesting part!-) the alteration of master (to insert projects randomly but without order changes), and finally random.shuffle(endofday); master.extend(endofday).
As I said the alteration part is the interesting one -- what about:
def random_mix(seq_a, seq_b):
iters = [iter(seq_a), iter(seq_b)]
while True:
it = random.choice(iters)
try: yield it.next()
except StopIteration:
iters.remove(it)
it = iters[0]
for x in it: yield x
Now, the mixing step becomes just master = list(random_mix(master, projects))
Performance is not ideal (lots of random numbers generated here, we could do with fewer, for example), but fine if we're talking about a few dozens or hundreds of items for example.
This insertion randomness is not ideal -- for that, the choice between the two sequences should not be equiprobable, but rather with probability proportional to their lengths. If that's important to you, let me know with a comment and I'll edit to fix the issue, but I wanted first to offer a simpler and more understandable version!-)
Edit: thanks for the accept, let me complete the answer anyway with a different way of "random mixing preserving order" which does use the right probabilities -- it's only slightly more complicated because it cannot just call random.choice;-).
def random_mix_rp(seq_a, seq_b):
iters = [iter(seq_a), iter(seq_b)]
lens = [len(seq_a), len(seq_b)]
while True:
r = random.randrange(sum(lens))
itindex = r < lens[0]
it = iters[itindex]
lens[itindex] -= 1
try: yield it.next()
except StopIteration:
iters.remove(it)
it = iters[0]
for x in it: yield x
Of course other optimization opportunities arise here -- since we're tracking the lengths anyway, we could rely on a length having gone down to zero rather than on try/except to detect that one sequence is finished and we should just exhaust the other one, etc etc. But, I wanted to show the version closest to my original one. Here's one exploiting this idea to optimize and simplify:
def random_mix_rp1(seq_a, seq_b):
iters = [iter(seq_a), iter(seq_b)]
lens = [len(seq_a), len(seq_b)]
while all(lens):
r = random.randrange(sum(lens))
itindex = r < lens[0]
it = iters[itindex]
lens[itindex] -= 1
yield it.next()
for it in iters:
for x in it: yield x
Use random.shuffle to shuffle a list
random.shuffle(["x", "y", "z"])
How to fetch a random element in a list using python:
>>> import random
>>> li = ["a", "b", "c"]
>>> len = (len(li))-1
>>> ran = random.randint(0, len)
>>> ran = li[ran]
>>> ran
'b'
But it seems you're more curious about how to design this. If so, the python tag should probably not be there. If not, the question is probably to broad to get you any good answers code-wise.
Combine all 3 lists into a DAG
Perform all possible topological sorts, store each sort in a list.
Choose one from the list at random
In order for the elements of the "project" list to stay in order, you could do the following:
Say you have 4 project tasks: "a,b,c,d". Then you know there are five spots where other, randomly chosen elements can be inserted (before and after each element, including the beginning and the end), while the ordering naturally stays the same.
Next, you can add five times a special element (e.g. "-:-") to the daily list. When you now shuffle the daily list, these special items, corresponding to "a,b,c,d" from above, are randomly placed. Now you simply have to insert the elements of the "projects" list sequentially for each special element "-:-". And you keep the ordering, yet have a completely random list regarding the tasks from the daily list.

Categories