-
-
Notifications
You must be signed in to change notification settings - Fork 655
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Alphametics #159
Alphametics #159
Conversation
Well this will be a fun one. Especially fun to benchmark. How about if we make it return a ten character string though, like "OMY--ENDRS" and put the solutions in the test cases. We could either restrict test cases to puzzles with zero or one solutions, or we could could handle multiple solutions by allowing any correct solution or requiring a list of all correct solutions. Part of my motivation is reducing the computations required by the test program. The more work the test program has to do, the more chance of a bug in the test program. |
You may be right about the tests being too complex. When I read your comment I realized that there's a bug in the tests, they don't check for uniqueness of digits. So generating valid output using some existing alphametics tools should be a better approach. And I bet there are plenty of alphametics tools, since this whole problem just screams constraint programming. |
Aargh, and what's worse, my example code is non-deterministic, it only sometimes gives a correct result. |
@soniakeys Do you think a bonus exercise that requires the user to find all solutions to math+code=same (156 solutions) would make sense here? |
Regarding return value, I kind of like the fact that the test code can print out a nice graphical representation of the solution as it really helps when debugging. At the same time, if the test code only checks against a list of valid outcomes it only would need a small bit of extra logic to transform a map as it is now into a string like "A=3 C=1 D=5 E=6 H=0 M=2 O=9 S=4 T=7". So that may be a good middle-of-the-road solution. |
It was fun. I posted a rendition here https://github.com/soniakeys/xgo/commit/5251d037b52516c0f3e1277b63de1711f6ac715f The example is completely brute force, so it takes several seconds. |
What's the status of this one? |
Not clear which solution to merge. @soniakeys solution is IMHO better, but we never got around to making an actual decision. |
This looks very cool! Was there any progress on making a decision or should we close the PR? |
aRunes, bRunes, cRunes := prepareRunes(a, b, c) | ||
|
||
// Setup the machinery for solving in parallel. | ||
resultChan := make(chan map[rune]int) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The concurrency here is pretty confusing.
You might try handling the waiting here in the caller rather than giving the waitgroup to the step solver.
So something like
go func() {
solveStep(...)
waitGroup.Done()
}()
Or alternatively handle the concurrency at a lower level may help clean this up a bit as I see you are also adding to the waitgroup in the solveStep
fn, which is recursive.
Cancellation may also be better served by a context.WithCancel
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may also be helpful to resolve this w/o concurrency and then add it in if needed only after you have a clean solution.
aRune, bRune, cRune := aRunes[0], bRunes[0], cRunes[0] | ||
c, cFound := acc.solution[cRune] | ||
for _, a := range availableDigits(aRune, acc, 0, 0) { | ||
for _, b := range availableDigits(bRune, acc, aRune, a) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interestingly, this looks like a case for recursion (which you are doing below), but are not doing here.
return result | ||
} | ||
|
||
func solveStep(aRunes, bRunes, cRunes []rune, acc accumulator, ipc *ipc) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
solveStep
should probably always return a value rather than sending it on a channel, it may help to clean up how the concurrency is handled.
Hi people, It seems I deleted my version from last year and I really have no memory of it. I did just rewrite a single-thread brute force solution that passes tests in about 7 seconds on my machine. I could repost it... Something faster would sure be nice. I confess I haven't studied at Peter's solution. Is it faster? Maybe something clever has been posted in one of the other languages that could be ported? There was a thing that showed a big table of exercises implemented in each language. Does that still work? Has anyone looked at this new language picat that won some recent awards? I tried but their doc is pretty terse if you're not up on concepts of logic programming. (Prolog was too long ago for me.) I really don't have good ways to solve constraint problems in Go. I coded Knuth's DLX once but that's an ugly mess of pointers. I think I coded a 2-SAT solver once. None of that helps, I know, just rambling. |
About this particular PR - since it seems like the original author is not currently to make changes, and the Allow maintainers to make changes option did not exist at the time, I think it is not possible to progress with this PR. Of course, if the author returns we will happily reconsider. For now, it seems like the thing to do is to close it and let any other interested party open a PR, since then that person will be able to make changes in response to feedback. Why not just merge it in its current state, you ask? As I see it, it is just that it needs to be added to config.json - and don't forget that we now have a https://github.com/exercism/x-common/blob/master/exercises/alphametics/canonical-data.json from which this exercise should draw its test cases unless there is very strong reason to deviate. If someone wishes to make use of the work already done in this PR, that is acceptable as well, with credit to the original author. We are of course available to review the revised work.
I would welcome it. Caution though, I suspect it may run for quite a long time on the new test case with 10 letters, since that's 10! permutations (you said it was brute force so I guessed at this, I don't know for sure).
I am not 100% sure, but it looks like the Travis result says it is passing all tests in about 0.1 seconds. Again, caveat because we don't know what will happen with the new test cases (in particular, if this code only handles two terms, it can't handle some of the new test cases)
I will point to exercism/ruby#469 - if you don't want to read all the code, I'll explain what goes on in their example.rb. The same thing happens in the example.go here. This only works if all problems are addition. canonical-data.json only has addition, but F# and Lua tracks have non-addition tests so they don't use this technique. Rot13 for those who don't want to be spoiled and figure it out for yourself. rot13(fbyir bayl bar pbyhza ng n gvzr!)
I remember seeing the table you speak of. It's slipped my memory. These days I only use http://x.exercism.io/problems/alphametics |
See exercism/problem-specifications#64.
I hope the example is somewhat readable, it was a challenging example to make.