I made a simple sudoku solver! But I need some help!

Hey all,

I've been fiddling around to create a sudoku solver!
https://claring.outsystemscloud.com/SudokuSolver/Sudoku

It works for rather simple sudoku's, but when facing some difficulties (multiple paths to figure out the solution) it stops working, only giving you some suggestions.....

It seems I can't make a recursive function within a loop (I have a list, which I pass into a function, inside this function there is a possibility to check every branch, by passing the same list but with a different input each time, it does this until it finds the solution), though by doing this the Outsystems platform says an iteration is not possible because the list is already being iterated.
Making a duplicate of the list is also not working because the platform immediately says that creating a duplicate while iterating a list is not allowed aswell...

I'm working in P11 and was hoping somebody could help me complete this as a full proof sudoku solver!

Though, if you could tell me if this is even possible or not that would also be a great help (it would be a shame if this would not be possible to create a recursive function/loop since that would greatly limit the power of the platform for more advanced algorithms).


Cheers, Joey.

Hi Joey,

yes, there is no recursive functions in Outsystems. After all, its not object orientated.
But hey, you always have .NET, and with Integration Studio, you wrap your code, and call it from outsystems.

Be sure though to create a proper management over the function, otherwise, it can overconsume resources.

With best regards,
Slavi Popov

Slavi Popov wrote:

Hi Joey,

yes, there is no recursive functions in Outsystems. After all, its not object orientated.
But hey, you always have .NET, and with Integration Studio, you wrap your code, and call it from outsystems.

Be sure though to create a proper management over the function, otherwise, it can overconsume resources.

With best regards,
Slavi Popov


Hey Slavi,

I am aware I can just go to other languages to solve this (I would've done this in Python, but where's the challenge?)

I'm trying to create solutions using pure outsystems to show (and test) how far it can go.

Hi. More advanced algorithms are usually built-in using Integration Studio as you get a better performance using native code. 

But you can, instead of using for loops, try to use a while loop using and IF widget and to access a certain position, you would do something like MySudoku.List[i].Cell for example. You would also need to manage the positions youself.


Hope this helps

Gabriel 

Gabriel Cardoso wrote:

Hi. More advanced algorithms are usually built-in using Integration Studio as you get a better performance using native code. 

But you can, instead of using for loops, try to use a while loop using and IF widget and to access a certain position, you would do something like MySudoku.List[i].Cell for example. You would also need to manage the positions youself.


Hope this helps

Gabriel 


Hey Gabriel,

Unfortunately that was one of the first things I tried haha!

Apperantly P11 is a bit smarter and recognizes you are still doing recursion within a list.

I do understand your desire to keep loyal to the platform/challenge.

Unfortunally you cant do anything with it.

And even if you can. The question resumes to practicality/efficiency.

For this reason, Outsystems have option to integrate with Java/.NET for exactly this reason.

With best regards,

Slavi 

Surely you can, you know it's a 9x9 matrix. You can try changing your structure to a Dictionary (check TextDictionary extension) and use as keys the matrix position 00, 45, etc

Solution

Ok, I've read this so far, and it seems there's some misinfomation going on. I'll try to correct:

  1. It is perfectly possible to use recursive Actions in general. Also, recursiveness has absolutely nothing to do with object orientation, and neither is there a "recursion within a list" as such (but see below).
  2. When you do not use a For Each, the list is not being iterated, so using recursion in that case is possible.

Now, what's going on is this: in general, within the same Module, Lists are being passed by reference. That means that there's no copying of the List when it's used as Input Variable of another Action; instead, a reference (or, if you like, pointer) to the List is passed. That means that the entire List, including it's state (which includes whether it's being iterated or not) is available, and any changes to the List will be "seen" by the calling Action.

Note there are various exceptions to this general rule (like calling an Action in another Module, or calling an Action that uses a Record List instead of a List, or calling an Action that uses a compatible, but slightly different List etc.), but for calling an Action recursively, the above applies (since by definition it's in the same Module with the same Parameters). If the List cannot be passed by reference, a copy is made (with possible conversions), in which case it is iterated.

A list that's being iterated cannot be iterated again: there's only a single iteration state, so if a List is passed by reference to another Action, you cannot iterate over the List in that Action. However, in general, you would want to pass only the Current of a List to an Action inside a For Each, because why else would you loop over the List in the first place? (And yes, I understand solving Sudokus is an exception to this.)

So, how to solve your use case? The first possibility has already been mentioned: if you directly index the elements of the List, there is no iteration, so you can do that recursively. I would advise that in this case, as you'll still have the advantage of not having to copy the List. A second option would be to copy the List before you start the For Each, and pass the copied List to recursive call (and use the original List to For Each over). The downside is that you'll make a copy, which takes some time, but the upside is that you don't need to write out your own while-loop.

Solution

Kilian Hekhuis wrote:

Ok, I've read this so far, and it seems there's some misinfomation going on. I'll try to correct:

  1. It is perfectly possible to use recursive Actions in general. Also, recursiveness has absolutely nothing to do with object orientation, and neither is there a "recursion within a list" as such (but see below).
  2. When you do not use a For Each, the list is not being iterated, so using recursion in that case is possible.

Now, what's going on is this: in general, within the same Module, Lists are being passed by reference. That means that there's no copying of the List when it's used as Input Variable of another Action; instead, a reference (or, if you like, pointer) to the List is passed. That means that the entire List, including it's state (which includes whether it's being iterated or not) is available, and any changes to the List will be "seen" by the calling Action.

Note there are various exceptions to this general rule (like calling an Action in another Module, or calling an Action that uses a Record List instead of a List, or calling an Action that uses a compatible, but slightly different List etc.), but for calling an Action recursively, the above applies (since by definition it's in the same Module with the same Parameters). If the List cannot be passed by reference, a copy is made (with possible conversions), in which case it is iterated.

A list that's being iterated cannot be iterated again: there's only a single iteration state, so if a List is passed by reference to another Action, you cannot iterate over the List in that Action. However, in general, you would want to pass only the Current of a List to an Action inside a For Each, because why else would you loop over the List in the first place? (And yes, I understand solving Sudokus is an exception to this.)

So, how to solve your use case? The first possibility has already been mentioned: if you directly index the elements of the List, there is no iteration, so you can do that recursively. I would advise that in this case, as you'll still have the advantage of not having to copy the List. A second option would be to copy the List before you start the For Each, and pass the copied List to recursive call (and use the original List to For Each over). The downside is that you'll make a copy, which takes some time, but the upside is that you don't need to write out your own while-loop.


Thanks Killian,

Duplicating the list right before calling the recursion seemed to work!
I had to store in some variables at what point I would like to branch though, after my initial loop was done I would then try to loop through each possible branch.

So I got everything working now!

But it seems the BPT (which is using the same functions....) is giving another "already iterating list" error...

Anyways, I had a simular issue with a local variable which I was filling inside the first part of the function and then iterating in the last part (for bruteforcing), apperantly the first call of the function is working fine.

But whenever I called the function from within the function it would give the same "cannot append/clear/iterating issues", though when duplicating this local variable before iterating it the issues would dissapear.

It would seem that there is still some sort of reference to a local variable being iterated even though it's a new instance of the function.

Either way, it's working now (apart from the BPT), with pure outsystems code, so I'm pretty content with the results.

Thanks!

Hi Joey

I need something similar: to calculate the max pallet height of a certain article based on it's WxLxH properties.

          calculate pieces per layer first, then the amount of layers => gives pallet height.

Would you be so kind to share your solver? 

Thank you in advance

Regards

Carolina