try. itself takes no more time than executing a short sentence like 2 + 3.
For placement of 111 1111 11111, find all the ways to rearrange
000000xxx, and for each one, replace the first x with 1110, the second
with 11110, the third with 11111.
To find all the ways to rearrange 000000xxx, find all the combinations
of (i.9) taken 3 at a time and install an x in the positions indicated.
To find the combinations of i.9 taken 3 at a time, use R. E. Boss's
method, see Combinations in the wiki.
Henry Rich
On 1/5/2018 6:26 PM, Nick S wrote:
Great suggestion. I actually played with it for quite a while last night,
got it all working. The solver can solve any puzzle I throw at it,
including those that barely have enough definition to hold together. I can
imagine puzzles it can't solve but those would have to be constructed to be
unsolvable.
I ended up using a lot of throws and trys and such. In some cases, the
only exit from a routine is a set of throws with flag variables set, as in
the example, to communicate, and it took a heck of a lot of code. In fact,
when I start the project, it takes way longer than it used to because there
is just way too much procedural code.
I wonder just how expensive try. is. I used to get solutions in the under
2 second range. Now I am getting solutions in the 3.5 second range. But
this seems to be totally based on the amount of processing. My first
solutions were solved without trial placement or backtracking, but the long
solutions require trial placement and backtracking. I just checked one of
my old testcases and it is still under 2 seconds cpu for a solution.
I also have hand coded backtracking, so that I can execute a trial solution
and easily give it up when it goes nowhere.
J makes it easy to create relatively complex data structures (like stacks
for backtracking environments). I ended up with a lot of code but most
other languages would have required five times as much code.
My basic concept was that I kept a recursion count. and in my try./catcht/
I used the entry level to control what I did - generally at any level where
I recursed, I would just throw. again and at the entry level I would put
out an error message and then return. So I don't get error messages when I
pick up the uncaught throw. Now I am catching all my throws and always
reporting errors or successes from the top level.
I appreciate all the advice I got while writing this. I will work on it a
bit more to clean up the messages and any other bugs I find. But I have
entered about 15 test cases, and it seems to be able to solve them all.
I have used a lot of if-then-else and case logic. I know, I should be
writing all this stuff as tacit one liners. But I don't see how. For
example, given the length of a boolean vector as 20, is there a way to
return all of the possible placements of three groups of 1's with length
of 3, 4, and 5, always in that order, and with at least one zero between
them? There can be zero or more zeros between the placements and the wall.
In other words, all the vectors that, when converted to a character string,
match this regular expression:
^0*1{3}0+1{4}0+1{5}0*$
0 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 0 0 0 matches
1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 0 0 0 does not. The first group is too
long. There are a very large number of possible wrong solutions, but there
are also a large number of valid solutions.
I could not figure out how to do it - so I ended up writing a recursive
routine where I place the first piece and then pass the rest of the work (a
shortened string and fewer placements) to the recursive call. The routine
has the advantage of letting me do early pruning of solutions where what I
have already placed violates constraints, and so forth. And I never have
to generate a huge binary table, just to filter and compress it to get the
results that I need for the solution.
I tried using adverse. For me it was a miserable failure - I didn't
realize that (u y)::(error yy) was probably returning nouns, while adverse
wants verbs as you showed. I have not tried using generated errors. What
is fun about this language, for me, is that scutwork (coding loops to
compare arrays or to move arrays) vanishes, while you can concentrate on
the logic of your program.
On Sun, Dec 31, 2017 at 11:28 AM, Ian Clark <[email protected]> wrote:
What's "normal" and what's an "error"? (Or, for that matter, a "crash"?)
When looking for the best solution to a coding problem, we can be prisoners
of our emotive use of language. Way back in IBM in the 1980s I recall the
end-user of a bespoke app written in APL picking up the phone in fury when
it spat out at her the all-too-familiar APL message:
RANK ERROR
– she thought the coder was being gratuitously offensive.
Stripped of its pejorative connotations, error recovery is just a way of
letting a deeply nested function escape and cut back the function stack –
and to do it in a way that doesn't look to the end-user like a coding
error. Or conversely, treating her to the sight of a raw coding error when
she'd appreciate a polite message geared to her needs and competency.
I use (::) a lot for this purpose. Far from being "ugly" I think it is
clean and respectable, avoiding the need for (…but not precluding) a
cumbersome system of error diagnostics – which then needs debugging in its
own right.
It also establishes a clear separation between "normal" code and
special-case handling (including error recovery), which lets you design the
former and then bolt-on as much of the latter as you need, and no more —
which to my mind (try./catch.) doesn't.
Paste this into a temp script and run it:
————————————————————————————————————————
NB. Use of (::) to escape to the session in a clean and respectable way.
NB. Avoid tainting the escape route with disapproval
NB. by using "general" not "normal" and "special" not "error".
myApp=: general :: special
general=: verb define
general1 y
)
general1=: verb define
NB. nest it deeper
addOne y
)
addOne=: verb define
NB. recognise special cases...
if. y<0 do. @@ end.
if. y>99 do. @@ end.
NB. else handle the general case...
y+1
)
special=: verb define
'myApp: cannot handle the argument: ' , ":y
)
————————————————————————————————————————
Running the app…
myApp 5 NB. handles general case ok
6
myApp _5 NB. rejects y<0
myApp: cannot handle the argument: _5
myApp 100 NB. rejects y>99
myApp: cannot handle the argument: 100
myApp '?' NB. forces a syntax error
myApp: cannot handle the argument: ?
Now, crashing (general) by executing (@@) is not everyone's idea of "clean
and respectable". But worse – you can't tell a deliberate crash from an
accidental one, as (myApp'?') shows.
However instead of (@@) you can signal a quasi-error with your own private
error number, and progressively code just the error diagnostics you need
into verb: (special) to report any bona-fide coding errors you haven't
fixed yet.
NuVoc explains how:
http://code.jsoftware.com/wiki/Vocabulary/ErrorMessages#Defi
ning_your_own_error_conditions
Thus you could redefine (addOne) and (special) like this…
————————————————————————————————————————
addOne=: verb define
NB. recognise special cases...
if. y<0 do. signalErrorNumber 255 end.
if. y>99 do. signalErrorNumber 99 end.
NB. else handle the general case...
y+1
)
special=: verb define
select. latestErrorNumber''
case. 99 do. 'myApp: cannot handle y>99: ' , ":y
case. 255 do. 'myApp: cannot handle y<0: ' , ":y
case. do. latestErrorMessage''
end.
)
signalErrorNumber=: 13!:8
latestErrorNumber=: 13!:11
latestErrorMessage=: 13!:12
————————————————————————————————————————
Now running the app…
myApp 5 NB. handles general case ok
6
myApp _5 NB. rejects y<0
myApp: cannot handle y<0: _5
myApp 100 NB. rejects y>99
myApp: cannot handle y>99: 100
myApp '?' NB. forces a coding error
|domain error: addOne
| y <0
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm
---
This email has been checked for viruses by AVG.
http://www.avg.com
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm