# Weekly Challenge

Solve the challenge, share your solution and summit the ranks of our Community!
###### IDEAS WANTED

We're actively looking for ideas on how to improve Weekly Challenges and would love to hear what you think!

Submit Feedback
We've recently made an accessibility improvement to the community and therefore posts without any content are no longer allowed. Please use the spoiler feature or add a short message in the message body in order to submit your weekly challenge.

## Challenge #200: Sudoku Solver

Highlighted
7 - Meteor

First challenge .. I did the beginner solution which was good to you learn as you go.

I'll leave Intermediate & Advanced for just now.

Spoiler

Highlighted
7 - Meteor

This was some nice parsing practice. As a beginner, this challenge has taught me I need to get better at RegEx expressions and the tool itself. My solution was very redundant using the formula tool, but hey, that's the beauty of Alteryx, it can be as simple or complex as you need to get the solution.

Highlighted
8 - Asteroid

Never considered myself at the advanced level, so haven't done the second puzzle, but I'm pretty sure if I was good at Macros, I could alter my solution a tiny bit and solve that section too. Maybe one day soon!

Highlighted
11 - Bolide

All three complete.

Spoiler

Highlighted
Alteryx Certified Partner

What a great way to celebrate Weekly Challenge #200!

Sudoku is "a denial of service attack on human intellect"

It has been a tremendous journey so far, and I am no way near to have solved 200 challenges myself, but this one deserved some extra effort.

I almost feel like writing a blog post on how I did it, but for now you have to take a peak below:

Spoiler
I do truly believe that almost everything can be solved in Alteryx one way or another, but I will admit, that the intermediate and advanced puzzle was a too big nut for me to crack

Luckily Alteryx does support the usage of R or Python in this case, so that was my approach here.

Beginner & Intermediate

So the Beginner part was dead easy due to the "hidden" tool Make Columns, and I can never stop mentioning @NicoleJohnson for showing me this tool. Learn it, like it, love it -you find this tool under the Laboratory tab.

Now for the second part the Intermediate, to solve the first beginner puzzle, I immediately thought of using Python, event thought I am not a Python developer, but it seem logic to me, to be a thing thousands had done before in Python.

My initial search brought me to this: Shortest Sudoku Solver in Python - How does it work? on Stack Overflow, and all though the explaining was thoroughly, I didn't make it work as intended, when trying to adapt this into Alteryx

So I researched a little bit further, and found this very nice tutorial Solving Every Sudoku Puzzle by Peter Norvig.
Based on this example, I was able to adapt the logic and put it into Alteryx Python component

``````#################################
# List all non-standard packages to be imported by your
# script here (only missing packages will be installed)
from ayx import Package
Package.installPackages(['pandas','numpy'])

#################################
from ayx import Alteryx

#print(df.iloc[0,0])

puzzle = df.iloc[0,0]

#################################
## Solve Every Sudoku Puzzle
## See http://norvig.com/sudoku.html

def cross(A, B):
"Cross product of elements in A and elements in B."
return [a+b for a in A for b in B]

digits   = '123456789'
rows     = 'ABCDEFGHI'
cols     = digits
squares  = cross(rows, cols)
unitlist = ([cross(rows, c) for c in cols] +
[cross(r, cols) for r in rows] +
[cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs in ('123','456','789')])
units = dict((s, [u for u in unitlist if s in u])
for s in squares)
peers = dict((s, set(sum(units[s],[]))-set([s]))
for s in squares)

################ Parse a Grid ################

def parse_grid(grid):
"""Convert grid to a dict of possible values, {square: digits}, or
return False if a contradiction is detected."""
## To start, every square can be any digit; then assign values from the grid.
values = dict((s, digits) for s in squares)
for s,d in grid_values(grid).items():
if d in digits and not assign(values, s, d):
return False ## (Fail if we can't assign d to square s.)
return values

def grid_values(grid):
"Convert grid into a dict of {square: char} with '0' or '.' for empties."
chars = [c for c in grid if c in digits or c in '0.']
assert len(chars) == 81
return dict(zip(squares, chars))

################ Constraint Propagation ################

def assign(values, s, d):
"""Eliminate all the other values (except d) from values[s] and propagate.
Return values, except return False if a contradiction is detected."""
other_values = values[s].replace(d, '')
if all(eliminate(values, s, d2) for d2 in other_values):
return values
else:
return False

def eliminate(values, s, d):
"""Eliminate d from values[s]; propagate when values or places <= 2.
Return values, except return False if a contradiction is detected."""
if d not in values[s]:
values[s] = values[s].replace(d,'')
## (1) If a square s is reduced to one value d2, then eliminate d2 from the peers.
if len(values[s]) == 0:
return False ## Contradiction: removed last value
elif len(values[s]) == 1:
d2 = values[s]
if not all(eliminate(values, s2, d2) for s2 in peers[s]):
return False
## (2) If a unit u is reduced to only one place for a value d, then put it there.
for u in units[s]:
dplaces = [s for s in u if d in values[s]]
if len(dplaces) == 0:
return False ## Contradiction: no place for this value
elif len(dplaces) == 1:
# d can only be in one place in unit; assign it there
if not assign(values, dplaces[0], d):
return False
return values

def string_return(values):
return "".join(values.values())

#################################
solved = string_return(parse_grid(puzzle))

#print(solved)
#print("Dataframe" , df, sep='\n')

#df.loc[1] = [solved]
df.insert(1,"solutions",[solved], True)

#print("Dataframe" , df, sep='\n')

Alteryx.write(df,1)

#################################``````

It was not my first rodeo with Alteryx and Python, and for beginners I can highly recommend @SydneyF excellent Tool Mastery on Python

One of the key things to know, is that when using the Python tool input and output is done in Pandas Data Frame, but once you get at hang of this, it's no biggie.

So if you examine my code (I did mention I am not a Python developer right?)  you can see I do some extraction of the puzzle string and in the end converting the result back into a string I then append to the Pandas Data Frame and output it again,

It this should have been even more nicer, I should have made the logic so you actually could parse multiple puzzles at the same time, and the iterate over them, but oh well - there is always room for improvement.

So using Python did solve the Beginner puzzle okay fast
Python Execution Time

So the Advanced solution was just to use the same Python code again, and yes, I should obviously have encapsuled this in a macro, since I am using the same code more than once, but apparently I am a slow learner 🙂🙂

And apparently, the Python code is not that much longer in solving this harder puzzle

So If you have read so far, I hope you enjoyed this explanation.

Raise you to the top 😄😄

Still Climbing
/Verakso

Highlighted
7 - Meteor

My Solution for this challenge:

1) Beginner level

Spoiler

2) Intermediate level

Spoiler

• Workflow
Spoiler
• Macro
Spoiler

Highlighted
8 - Asteroid
Spoiler

Highlighted
8 - Asteroid

Solved Beginner and Intermediate . Good one.

Highlighted
Alteryx Partner

Phew, got there in the end with the intermediate solution! It's a bit long, so I'll only put a screenshot of the beginner's part

Spoiler

Highlighted
Alteryx Partner
Spoiler