The Search for the “perfect” Advent Calendar (involves Python and Processing)
blog.jgc.org
blog.jgc.org
The best known solution is plastic numbers. I expect you could use something like that here rather than brute force.
http://extremelearning.com.au/unreasonable-effectiveness-of-...
(Ordered dither matrices might offer another good starting point.)
Lowest value found, has vertical symmetry (notice how (1,24), (2,23), (3,22), (4,21) and so on are paired)
[[14 7 19 12 5 17]
[21 9 2 24 22 10]
[ 4 16 23 1 3 15]
[11 18 6 13 20 8]]
375.923809971073
Highest value found, has rotational symmetry (see how the path from 1-24 is almost like a squished Hilbert curve) [[ 6 7 10 11 23 24]
[ 5 8 9 12 22 21]
[ 4 3 13 16 17 20]
[ 1 2 14 15 18 19]]
529.6200384399018
Code is at https://gist.github.com/jffry/fab43b5b65499c3f513fea70159780.... Probably full of new-to-Rust mistakes, so please let me know where I've strayed from the light if you're particular about Rust!As mentioned elsewhere I'm very curious about how this generalizes to grid sizes other than 6x4
"Cortex"
[[ 6 7 10 11 23 24]
[ 5 8 9 12 22 21]
[ 4 3 13 16 17 20]
[ 1 2 14 15 18 19]]
529.6200384399018
The path traced from 1-24 is rotationally symmetric and folds up in on itself sort of like a Hilbert curve.And now I'm curious how this problem might look for other MxN aside from 6x4
EDIT: Played around a bit myself, here's a quite pleasing order I came up with:
1 9 17 24 16 8
5 13 21 20 12 4
3 11 19 22 14 6
7 15 23 18 10 2
Python snippet here: https://pastebin.com/XNvjEmxcWhat additional constraint could you add to shake this up? Perhaps a rule that, as well as number adjacency being penalized, adjacent distances between consecutive numbers also get penalized?
[[ 1 9 17 24 16 8]
[ 5 13 21 20 12 4]
[ 3 11 19 22 14 6]
[ 7 15 23 18 10 2]]
400.634917287
Compare with this one found using the 'genetic algorithm': [[ 9 4 18 10 15 20]
[16 21 12 1 22 7]
[ 2 6 24 5 17 13]
[14 8 19 11 23 3]]
386.229085028 [[11 16 8 13 2 20]
[18 21 5 24 7 15]
[ 3 9 1 19 22 4]
[14 23 6 17 10 12]]
382.46224448143795It's basically the same as the swap() function in advent.py except you sometimes allow swaps that result in worse scores according to an ever-decreasing probability ("temperature"). The added controlled randomness allows you to break out of local minima at the start and hone in on the local optimum towards the end.
EDIT: after a little tweaking of the temperature schedule I got 377.59 after 10K swaps.
8 20 15 10 5 17
13 4 22 12 23 1
18 2 24 21 3 7
11 6 16 9 14 19
gets a score 376.9629. This came from starting with a random matrix, trying all possible swaps and taking the best one, and iterating until a local minimum is reached. np.matrix('12 19 6 14 4 9; 8 17 1 24 22 16; 21 3 23 2 20 11; 15 10 5 13 18 7')
which has a score of 376.899. This was produced in 20K swaps with the line: best, score = anneal(n=10000)
which was then further refined with: best, score = anneal(start_temp=0.2, advent=best, n=10000)
where anneal() is defined here: https://pastebin.com/xBVGJfQdThe score() function is a bit slow at the moment. If I get some time later, I might see if I can speed it up a bit, which will allow for some faster experimentation.
EDIT: replaced code with pastebin link to save space in comments
[[12, 19, 6, 14, 4, 9],
[ 8, 17, 1, 24, 22, 16],
[21, 3, 23, 20, 2, 11],
[15, 10, 5, 13, 7, 18]]
Score = 376.6144674353488Found by increasing number of iterations to 100000
Sim.annealing followed by an exhaustive pair-swap search to find the local minimum would have found this more efficiently. Possibly there are some further refinements left -- I haven't run the exhaustive pair search on the above!
[[ 9 15 4 20 6 12]
[18 23 11 1 22 17]
[ 7 2 16 24 3 8]
[13 21 5 10 19 14]]
376.364049355 [[17 11 6 19 14 8]
[ 4 22 24 1 3 21]
[ 9 15 2 23 12 16]
[13 20 7 18 5 10]]
375.998672775885I've gotten close, but not cracked it yet. I was wondering if anyone would break the 376.0 barrier!
https://gist.github.com/jffry/fab43b5b65499c3f513fea70159780...
https://rjp.is/calendars/topthree.png
Compare and contrast the original set from @jgc's article:
Finally got a < 376.0 from my own code using simulated annealing method...
375.998672775885
[[13 20 7 18 5 10]
[ 9 15 2 23 12 16]
[ 4 22 24 1 3 21]
[17 11 6 19 14 8]]
...only to realise it's the same as yours, but with the rows reversed! Rather surprised, but I now wonder if there is only a small number of very-low-scoring solutions. So perhaps this is less of a coincidence than it first appears.I'm now using a much more aggressive temperature drop-off to find decent candidates early, followed by a tempering phase to search for nearby solutions, and a final cool-off to refine the final answer. I'm still using only random pair swaps in Python, so probably wasting a lot of cycles, but I'm still quite surprised how quickly it converges to some pretty decent scores. Beyond that I'm just going to try lots of random starting layouts.
I'm interested to see if my method can find any of the other posted solutions or (fingers crossed!) any new ones, but I may need to crunch through a lot more candidates... I will have to translate from Python into something faster to up my game!
37 0
38 2377
39 1103812
40 16535778
41 39376324
42 29525491
43 10609914
44 2394340
45 395239
46 51463
47 4880
48 363
49 19
50 0