Joined: 3/14/2008
Posts: 152
Location: United Kingdom
As there were a few requests for this game in the wish list topic, and it looked quite interesting, I decided to have a try at TASing the challenge mode of Polarium. Here is what I have so far: Link to video I've noticed a few places where it isn't optimal, so i'll redo it over the next few days. Edit: Updated the link since I deleted the old video over 2 years ago
Editor, Experienced player (734)
Joined: 6/13/2006
Posts: 3300
Location: Massachussetts, USA
Looks good! Fast paced, and the end result is what I expected. I also liked how you noodled with the stylus before the next puzzle would fall into place. it seems a little weird that you can finish the puzzle before it falls into place; that ruins the difficulty of it a little bit, but oh well. Fix what you need to fix and finish it, I say!
Homepage ☣ Retired
Post subject: Puzzle levels 1-10
Joined: 12/21/2011
Posts: 3
Location: UK
I've started looking at the puzzle levels in Polarium (U), the following test file does the first 10 levels. http://dehacked.2y.net/microstorage.php/info/1204872092/Polarium%20-%20WIP%201.dsm Edit: Updated file with levels 1-20 - http://dehacked.2y.net/microstorage.php/info/718847732/Polarium%20-%20WIP%202.dsm As you can see there's some room to play after the actual puzzle has been solved but this test run doesn't make much use of that yet. All constructive criticism appreciated.
Post subject: Polarium (1-20) wip-1: youtube
Joined: 3/18/2006
Posts: 971
Location: Great Britain
Link to video
Dasaan wrote:
Edit: Updated file with levels 1-20 - http://dehacked.2y.net/microstorage.php/info/718847732/Polarium%20-%20WIP%202.dsm As you can see there's some room to play after the actual puzzle has been solved but this test run doesn't make much use of that yet. All constructive criticism appreciated.
Editor, Player (44)
Joined: 7/11/2010
Posts: 1029
I'm not convinced that Puzzle mode is the best for a TAS; it's just a sequence of entering the fastest solution to each level, one after the next, and unless there's some sort of crazy glitch it's simply going to be reasonably unimpressive as a TAS. Challenge mode would seem to give more scope for interesting play, especially given that you can accelerate the drops of puzzle sections by swiping down on the cancel button. As for the run so far, there's at least one clear mistake: in puzzle 14 (and analogously in the very similar puzzle 18), you can solve it much faster (no matter whether it's the number of squares or the number of turns in the path that matters for how long the puzzle takes to solve; I'm not sure which it is). Instead of the crazy convoluted path you take, you should start at the top-left corner, use your solution for the bottom two rows, then just hit the top-right corner, to make the resulting rows white/black/black; that'd be a much faster solution to enter. I'm also not convinced this is the only puzzle on which a similar solution would save time, but it's much closer in some of the others, and I'm not certain whether your solution is the best or not. Puzzle 9, there's reasonably simple alternative solutions black/white/black and black/white/white; I'm not sure if either is faster than the black/black/black you use, but it seems plausible. Puzzle 10, white/white/white/black is probably worth considering; and in puzzle 15, there may be a faster route to recolour the same cells (involving spending less time going around the outside of the puzzle).
Joined: 12/21/2011
Posts: 3
Location: UK
Nope, not the most entertaining movie. To be fair though this was just something to have a fiddle with over the holidays and I thought I might as well share what I'd done just on the off chance that someone was interested. edit: Yep b/w/b in puzzle 9 looks to be much faster with far fewer direction changes required. edit: I'll need to crunch the numbers on Puzzle 10, w/w/w/b doesn't jump out as a clear cut winner. Puzzles 14 and 18 certainly are sub-optimal in my movie. Doing the maths my route is 45 frames long and yours would be 29 frames long making a saving of 16 frames for each of those 2 puzzles I'm not seeing a hugely better solution for puzzle 15 yet, only a 2 frame saving by tweaking the existing solution. For anyone interested in the mechanics: - It takes 3 frames to tap a square of input - To move to an adjacent square (up/down/left/right) it takes an additional 3 frames of input - To move to a non adjacent square (up/down/left/right) any distance away takes an additional 4 frames of input - The final move (double tap) requires an additional 4 frames of input (1 of no input and 3 to complete the double tap) For example: To move from the left square to the adjacent right square [][] takes 6 frames. 3 to select the left square and 3 to select the right square. To move from the left square to the far right square [][][][] takes 7 frames. 3 to select the left square, 1 of no input, then 3 to select the far right square. To move from the bottom square to the top right [][] [] takes 9 frames, 3 to select the bottom square, 3 to select the top left and 3 to select the top right. To move from the bottom square to the top right [][][][] [] [] takes 11 frames, 3 to select the bottom square, 1 of no input, 3 to select the top left square, 1 of no input and 3 to select the top right square.
Editor, Player (44)
Joined: 7/11/2010
Posts: 1029
Hmm, now I almost want to write a script for solving Polarium puzzles optimally. It's just that I have so much else to do…
Joined: 3/14/2008
Posts: 152
Location: United Kingdom
ais523 wrote:
Hmm, now I almost want to write a script for solving Polarium puzzles optimally. It's just that I have so much else to do…
Did you ever get around to doing anything with that? I've been thinking about having another look at polarium recently and will probably try to write my own program to solve the puzzles (optimally). There is a solver program out there: http://notabdc.vip.sina.com/EngPage/e_solver.htm (scroll down a bit) which I used before but it doesn't always give optimal solutions (sometimes obvious due to it needlessly doing a loop on the outside when it could just do a straight line) and isn't open source (from what I can tell, but I could try emailing the author I guess). Although unless the higher levels of challenge mode are much harder than the early parts, having the most optimal solution would not actually save time there (just give you more time to doodle). Obviously being frame perfect is needed for the puzzle mode.
ais523 wrote:
I'm not convinced that Puzzle mode is the best for a TAS; it's just a sequence of entering the fastest solution to each level, one after the next, and unless there's some sort of crazy glitch it's simply going to be reasonably unimpressive as a TAS. Challenge mode would seem to give more scope for interesting play, especially given that you can accelerate the drops of puzzle sections by swiping down on the cancel button.
Should a "Full game" run consist of both the Challenge and puzzle modes though? Or would a tas of just the challenge mode be enough? Another consideration is the gba version which was actually made afterwards which did away with the challenge mode but has three (short) time attack modes and "daily" polarium which consists of 365 puzzles (I think). The gba version also includes some new mechanics such as areas of the outside that can't be "walked" on: http://duks.co.uk/i/rQ92.png , "colourless" tiles that disappear so long as all the other tiles on their row are the same colour: http://duks.co.uk/i/KH1f.png , these weird ones: http://duks.co.uk/i/dZgw.png which cause tiles above to drop when they disappear. Motion of the "cursor" in the gba is fairly simple as it's just one tile per 2 frames, but there's no way to go x number of tiles. I did a short test a few weeks ago of one of the time trial modes: http://www.youtube.com/watch?v=Hz_JF_6VdJw (I used the solver linked above and took out the obvious non optimal parts, but the solutions used here may still be sub optimal). I'm not sure but I think there may be random puzzles (or from a set) generated each time for the time attack but I'd have to check.
Editor, Player (44)
Joined: 7/11/2010
Posts: 1029
Challenge and Puzzle are clearly different categories, and as such would be separate movies. I think Challenge would be much more entertaining. (Also, I'd prefer to see the DS version, because it's what more people will be used to, not to mention the GBA's controls are reasonably awful for playing the game with. The two games could be done separately.) The higher levels of Challenge mode are indeed much harder; I have completed it on console, but only twice. Also, I have a feeling that the optimal strategy involves letting the screen fill via repeated downward swipes on the cancel button, then solving the entire screen optimally. I'm not convinced that single-stroke solutions are always possible for a Challenge mode puzzle that fills the whole screen, so luck manipulation may be useful there. Oh, and I never did write the solver, but now you've got me wondering about it again… EDIT: After looking at it, downswiping is going to be much faster because the main thing that slows down Challenge mode is the cutscene in which lines are eliminated. So you want to be able to remove as many lines as you can per stroke in order to get the top speed. This means waiting for the screen to fill, downswiping does that faster. (In case you don't know the trick, you put the stylus near the top of the cancel buttons and drag it downwards; it's mentioned in the manual, IIRC.)
Joined: 3/14/2008
Posts: 152
Location: United Kingdom
ais523 wrote:
EDIT: After looking at it, downswiping is going to be much faster because the main thing that slows down Challenge mode is the cutscene in which lines are eliminated. So you want to be able to remove as many lines as you can per stroke in order to get the top speed. This means waiting for the screen to fill, downswiping does that faster. (In case you don't know the trick, you put the stylus near the top of the cancel buttons and drag it downwards; it's mentioned in the manual, IIRC.)
Short video comparing the new and old methods, sort of: Link to video Edit: Just noticed now but the score on the old tas randomly jumps up to 15k?? I'm guessing this was an emulation glitch in 0.94+ Edit2: Proof doing multiple at a time is faster (could be even better if manipulated) Link to video On the left is the new one, and on the right is my old one from 2009. The old one was made on 0.94+ and new on 0.98 (is this what I should be using? The desmume page on tasvideos is outdated, and in the desmume thread gocha seems to be maintaining both 0.97 and 0.98) which means there is a slight emulation difference (first frame of input to skip the title screen is a few frames earlier on 0.98) and my old run is also suboptimal in the menu as well as swiping down late on the first block. However you can see from the video that the new method of swiping down multiple times at once is possibly faster as the 17th line appears on the scoreboard about 2 seconds earlier, though this is about what the mistakes lose so I'll have to test doing that method again just to make sure. I think the new method doesn't save much time because of the third reason below (animation slowing down). New things I've found out/remembered: Swiping down on the cancel button takes 8 + 1 frames of input (8 of holding down the stylus and 1 blank frame afterwards). However the game is somewhat picky about how those 8 frames are (can't have 4 at top 4 at bottom etc, but I know the general way it works and will make a macro to do it for me to avoid errors). Due to it pressing on the cancel button, you can't swipe down in the middle of drawing a path. This is annoying as it means you can't draw the complete route early while you are still swiping down, emphasizing the importance of optimal routes. You can only swipe down one "block" at a time, the next block can be swiped down 2 frames after the previous one stops moving, however, swiping down while the line elimination animation still works but the block does not come down until the end of the animation. Manipulation of the blocks is quite difficult and seems to depend only on stylus input when you are in the game (though I only tested buttons for a short number of frames in the future) or which frame you start challenge mode on (optimizing solver would be pretty much required to test this though, as it may be beneficial to wait for a certain number of frames before starting to get better puzzles, and hopefully after the first puzzle everything is possible to manipulate). I was so far only able to affect drops of blocks 5 into the future with my input (the doodling, as well as the way the puzzle is solved) but I didn't test this far ahead with button presses so they may have an effect too. As you can see from the video, an optimal solution will be required for at the very least the first two puzzles unless they are manipulated. I have used the polarium sovler I linked in my last post and made as many optimizations to the route it gives as possible (saving I think 4 frames on the first set of three: Original route given by solver (136 frames unless I calced wrong): (more) Optimal route I used (131 frames): I have contacted the creator of the solver to see if they can provide me the source code/help me with making my own solver so will hopefully get a reply, but if not I'll probably need help making my own solver since I'm not the best programmer and I'm not really sure where to start.
Player (137)
Joined: 9/18/2007
Posts: 389
Well... If I got the rules of this game right just by looking on the few images, then I got a better solution:
Joined: 3/14/2008
Posts: 152
Location: United Kingdom
For your those two: left = 121 frames, right = 103 (they look like they should work and I'll test them when I get home). I should probably try and solve them manually before using the solver (though I'm not really that good at doing the complex ones..).
Player (137)
Joined: 9/18/2007
Posts: 389
stage 09: stage 10: stage 14: stage 18: http://www.mediafire.com/?5rsb2dp0ala8875 I hope this gives you enough ideas for good solutions. I think that using the current solver is just a way to prove if there actually is some solution at all, nothing more. The problem "Does there exist a solution?" is in NP, but asking for the fastest solution is most likely something like O(3^n) where n is the amount of steps for the shortest solution (choose one new direction from "up", "down", "left", "right", but don't go back to the place you just came from). So... solving the easiest of all of them -- stage 14 -- would have taken about 3*5*4*3^8 = 393.660 attemps at worst. Well, most of these attempts would be cancelled rather quickly because the solution would become invalid. Brute-forcing the fastest solution might be possible (and it would even prove that the chosen solution is optimal), but this becomes a lot worse for bigger puzzles...
Player (137)
Joined: 9/18/2007
Posts: 389
Sorry, I found one more: The main idea is to avoid using the outer fields as much as possible. If you can avoid using the outer fields by walking through more fields in the middle this is always a good idea. The next idea: Try to avoid placing the two ends of the paths too close to each other.
Joined: 3/14/2008
Posts: 152
Location: United Kingdom
Once again thanks for the help, I seem to have trouble working out solutions that crossover between black and white directly (in the middle). I think I'll play through puzzle mode on my actual ds for a bit just so I get better at solving them. A note on "optimal" solutions - you have around 50 frames (I think it's exactly 50 but I'll check, my number may or may not include the no input frame after dragging down) between finishing dragging down and being able to "double tap" your solution, which means if you have one under 50 frames then it would be pointless to try and find a better one (in terms of the speed of the tas anyway). Edit: I think this may actually be completely wrong because of the puzzle completion animation delay Could you explain your maths from the previous post a bit more? I don't really see where your numbers come from (though I understand brute force would be exponential dependent on the size of the puzzle). Also, a somewhat relevant and funny quote from the Rubik's Cube tas submission thread:
Limne wrote:
More games should be beatable by automated solvers freely available on the internet.
Editor, Player (44)
Joined: 7/11/2010
Posts: 1029
Can you explain what affects the time of a route? Is it the number of squares in the route, the number of turns it makes, or some combination? EDIT: And for anyone who doesn't know but wants to help, the rules of the game are that your line has to either go through all the black squares on a row but no white squares, or all the white squares on a row but no black squares. You can choose which color you're aiming for separately for each row.
Joined: 3/14/2008
Posts: 152
Location: United Kingdom
Dasaan wrote:
For anyone interested in the mechanics: - It takes 3 frames to tap a square of input - To move to an adjacent square (up/down/left/right) it takes an additional 3 frames of input - To move to a non adjacent square (up/down/left/right) any distance away takes an additional 4 frames of input
See Dasaan's post above for some examples, but that basically sums it up. What this means is that a route that is shorter in the number of tiles than another may actually be longer timewise if it contains lots of single tile movements, since any straight line takes 4 frames no matter the distance.
Editor, Player (44)
Joined: 7/11/2010
Posts: 1029
Thanks for the timing explanation. So it mostly but not entirely depends on the number of turns in the route; if I do write this solver (I have ideas about it, but am not really sure if they'll work), a route costs 7 for any line in the same direction, or 6 if it has length 1. (Plus a constant, but that doesn't matter when comparing routes.) Right? EDIT: Ah no. Dasaan's post explains it in enough detail for me, though. Thanks everyone!
Player (137)
Joined: 9/18/2007
Posts: 389
duksandfish wrote:
Could you explain your maths from the previous post a bit more? I don't really see where your numbers come from
I just used FieldWidth*FieldHeight *4 (directions to choose from the starting point) * 3 (directions to choose from, as going back doesn't make sense) * 3 * 3 * 3 * ... This number is too big, I just wanted to find some upper limit. For example it includes paths like start->right->up->left->down which is invalid, and it doesn't matter which end of the path you choose, so it's 2 times too big. I think it should be possible to brute-force through all black-white-combinations (it's always 2048 or a lot less, so it shouldn't cause any trouble, most of them aren't solvable anyway), and check if the maze may be solvable. Then: count how many fields have to be changed, and how many outer fields must be used at least. Then search for solutions for all black-white-combinations which seem to be somewhat reasonable. Or if you want to make sure to find the best solution: search a path through every solvable maze.
Player (137)
Joined: 9/18/2007
Posts: 389
Yay, I could get a Polarium Solver working! It tests ALL starting points and ALL possible paths. When one is found, this one is printed out. This program solves stage 14, but it shouldn't be difficult to adjust it to let it work with every maze. Download PolariumSolver.lua
Language: lua

function deepcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in pairs(orig) do copy[orig_key] = deepcopy(orig_value) end else -- number, string, boolean, etc copy = orig end return copy end puzzlestring = { ".***.", "**.**", ".***." } puzzle = {} for y,str in ipairs(puzzlestring) do puzzle[y] = {} s = puzzlestring[y] for x = 1, string.len(s) do puzzle[y][x] = (string.sub(s, x, x) == ".") end puzzle[y][0] = "*" puzzle[y][string.len(s) + 1] = "*" end height = #puzzle width = #puzzle[1] - 1 for y = 0, height + 1, height + 1 do puzzle[y] = {} for x = 0, width + 1 do puzzle[y][x] = "*" end end function printpuzzle(p) local s = "" local puz = p.puzzle for y = 0, #puz do for x = 0, #puz[y] do local c = puz[y][x] if p.solutionrequired[y] == nil or p.solutionrequired[y] == "*" then if c == true then s = s .. " #" elseif c == false then s = s .. " ." elseif type(c) == "number" then s = s .. string.format("%3u", c) else s = s .. " " .. c end elseif p.solutionrequired[y] == true then if c == true then s = s .. " +" elseif c == false then s = s .. " -" elseif type(c) == "number" then s = s .. string.format("%3u", c) else s = s .. " " .. c end elseif p.solutionrequired[y] == false then if c == false then s = s .. " +" elseif c == true then s = s .. " -" elseif type(c) == "number" then s = s .. string.format("%3u", c) else s = s .. " " .. c end else s = s .. "!failure " .. y .. ";" .. x .. ";" .. tostring(c) .. ";" .. tostring(p.solutionrequired[y]) .. "!" end end s = s .. "\n\n" end print(s) end fifo = {} elementcount = 0 maxelements = 0 -- start an attempt for every starting point for y = 1, #puzzlestring do for x = 1, #puzzlestring[y] do current = { puzzle = deepcopy(puzzle), x = x, y = y, step = 1, solutionrequired = {} } current.solutionrequired[y] = puzzle[y][x] current.puzzle[y][x] = 1 --printpuzzle(current) table.insert(fifo, current) elementcount = elementcount + 1 maxelements = math.max(maxelements, elementcount) end end counter = 1 current = table.remove(fifo, 1) while(current) do print("counter: ".. counter .. "; elements: " .. elementcount .. "; max: " .. maxelements) printpuzzle(current) --check if this one solves the maze validvalues = 0 for y = 1, #puzzlestring do for x = 1, #puzzlestring[y] do if type(current.puzzle[y][x]) == "number" or ( current.solutionrequired[y] ~= nil and current.puzzle[y][x] ~= current.solutionrequired[y] ) then validvalues = validvalues + 1 end end end if validvalues == #puzzlestring * #puzzlestring[1] then print("!! best solution found !!") break end --check if it is possible to go one step up if --field limit hasn't been reached (current.y >= 1) and --we didn't already visit this place (type(current.puzzle[current.y-1][current.x]) ~= "number") and --visiting this place is allowed ( --place can be visited if it is on the outside (current.x == 0 or current.x == #puzzlestring[1] + 1 or current.y == 1) --we didn't visit any field on this row or (current.solutionrequired[current.y - 1] == nil) --we visit a field of the same colour or (current.solutionrequired[current.y - 1] == current.puzzle[current.y-1][current.x]) ) then newpuzzle = deepcopy(current) newpuzzle.step = newpuzzle.step + 1 newpuzzle.y = newpuzzle.y - 1 if newpuzzle.y >= 1 then if newpuzzle.puzzle[newpuzzle.y][newpuzzle.x] ~= "*" then newpuzzle.solutionrequired[newpuzzle.y] = newpuzzle.puzzle[newpuzzle.y][newpuzzle.x] end end newpuzzle.puzzle[newpuzzle.y][newpuzzle.x] = newpuzzle.step table.insert(fifo, newpuzzle) elementcount = elementcount + 1 maxelements = math.max(maxelements, elementcount) end -- check if it is possible to go one step down if --field limit hasn't been reached (current.y <= #puzzlestring) and --we didn't already visit this place (type(current.puzzle[current.y+1][current.x]) ~= "number") and --visiting this place is allowed ( --place can be visited if it is on the outside (current.x == 0 or current.x == #puzzlestring[1] + 1 or current.y == #puzzlestring) --we didn't visit any field on this row or (current.solutionrequired[current.y + 1] == nil) --we visit a field of the same colour or (current.solutionrequired[current.y + 1] == current.puzzle[current.y+1][current.x]) ) then newpuzzle = deepcopy(current) newpuzzle.step = newpuzzle.step + 1 newpuzzle.y = newpuzzle.y + 1 if newpuzzle.y <= #puzzlestring then if newpuzzle.puzzle[newpuzzle.y][newpuzzle.x] ~= "*" then newpuzzle.solutionrequired[newpuzzle.y] = newpuzzle.puzzle[newpuzzle.y][newpuzzle.x] end end newpuzzle.puzzle[newpuzzle.y][newpuzzle.x] = newpuzzle.step table.insert(fifo, newpuzzle) elementcount = elementcount + 1 maxelements = math.max(maxelements, elementcount) end --check if it is possible to go one step left if --field limit hasn't been reached (current.x >= 1) and --we didn't already visit this place (type(current.puzzle[current.y][current.x - 1]) ~= "number") and --visiting this place is allowed ( -- place can be visited if it is on the outside (current.y == 0 or current.y == #puzzlestring[1] + 1 or current.x == 1) -- or if we visit a field of the same colour or (current.solutionrequired[current.y] == current.puzzle[current.y][current.x - 1]) ) then newpuzzle = deepcopy(current) newpuzzle.step = newpuzzle.step + 1 newpuzzle.x = newpuzzle.x - 1 newpuzzle.puzzle[newpuzzle.y][newpuzzle.x] = newpuzzle.step table.insert(fifo, newpuzzle) elementcount = elementcount + 1 maxelements = math.max(maxelements, elementcount) end --check if it is possible to go one step right if --field limit hasn't been reached (current.x <= #puzzlestring[1]) and --we didn't already visit this place (type(current.puzzle[current.y][current.x + 1]) ~= "number") and --visiting this place is allowed ( -- place can be visited if it is on the outside (current.y == 0 or current.y == #puzzlestring[1] + 1 or current.x == #puzzlestring[1]) -- or if we visit a field of the same colour or (current.solutionrequired[current.y] == current.puzzle[current.y][current.x + 1]) ) then newpuzzle = deepcopy(current) newpuzzle.step = newpuzzle.step + 1 newpuzzle.x = newpuzzle.x + 1 newpuzzle.puzzle[newpuzzle.y][newpuzzle.x] = newpuzzle.step table.insert(fifo, newpuzzle) elementcount = elementcount + 1 maxelements = math.max(maxelements, elementcount) end current = table.remove(fifo, 1) elementcount = elementcount - 1 maxelements = math.max(maxelements, elementcount) counter = counter + 1 end
At the end, you get this result:
counter: 1532; elements: 519; max: 521
  *  *  *  *  *  *  *

  *  1  -  -  -  9  *

  *  2  3  -  7  8  *

  *  -  4  5  6  -  *

  *  *  *  *  *  *  *


!! best solution found !!
Note that this one doesn't minimize the amount of frames, it minimizes the amount of fields to visit. There's some more adjustment necessary for minimizing the amount of frames. It even works for stage 78, it just takes a lot longer (and if you don't utilize the symmetries in this one, you would need about 2.100.000 steps, and 140.000 stored mazes). Quite an evil one, the shortest solution requires 50 fields.
Editor, Player (44)
Joined: 7/11/2010
Posts: 1029
So, I had a go at writing a Polarium solver myself, and ended up with something massively sophisticated and overengineered. For anyone who's interested, here it is: http://nethack4.org/pastebin/polarium-solver.lua (Like other solvers here, I chose Lua for the potential to maybe implement into an emulator.) With luajit, this takes a couple of seconds for puzzle 100, and around 14 seconds for the 9 by 9 puzzle the latest TAS WIP starts with (after the "1"), to find the optimal solution in tiles and in frames. It's quite slow at puzzles with a lot of solutions, or a lot of red herrings; it works a little like I do when solving puzzles, although resorts to brute force at the end.
Player (137)
Joined: 9/18/2007
Posts: 389
Congratulations, you win the battle for the best program. I did some optimizations to my program (which is essentially brute-forcing the complete puzzle), and it gave me the same solution, but it required several hours for finding it:
counter: 1088987; elements: 18104; max: 46989; unsolvables removed: 396759
    *    *    5    6    7    8    9    *    *    *

    *    -    4    3    2    -   10   11   12    *

    *    -    -    -    1    -    -    -   13    *

    *    -   48   47   46    -   18   17   14    *

    *    -    -    -   45    -   19   16   15    *

    *   41   42   43   44   21   20    -    -    *

    *   40   39   38    -   22   25   26    -    *

    *    -    -   37    -   23   24   27    -    *

    *    -    -   36   35   34    -   28   29    *

    *    *    *    *    *   33   32   31   30    *
!! best solution found !!
I think your solver works correctly -- and much faster than my one. EDIT: The program doesn't work correctly for Stage 1:
44 solutions found.
Total solutions found: 52
Fastest solution (22 frames):
* * *-*-* * *
    |   |    
* . + . + . *
    |   |    
* . + . + . *
    |   |    
* . + . + . *
    |   |    
* . + . $ . *
    |        
* . + . $ . *
    |   |    
* * *-*-* * *

Shortest solution (16 tiles):
* * *-*-* * *
    |   |    
* . + . + . *
    |   |    
* . + . + . *
    |   |    
* . + . + . *
    |   |    
* . + . $ . *
    |        
* . + . $ . *
    |   |    
* * *-*-* * *

script finished running
script stopped.
It fails on stage 3:
Best attempt before brute-forcing:
*?*?A?*?A?*?*
?   ?   ?   ?
* . A . A . *
?   ?   ?   ?
* . A . A . *
?   ?   ?   ?
* . A?A?A . *
?     ?     ?
* . . A . . *
?     ?     ?
* . . A . . *
?     ?     ?
* . . A . . *
?     ?     ?
* . . A . . *
?     ?     ?
*?*?*?A?*?*?*

0 solutions found.
Total solutions found: 5962
Fastest solution (47 frames):
* * *-*-* * *
    |   |    
* . + . + . *
    |   |    
* . + . + . *
    |   |    
* . + $-+ . *
    |        
*-+ + . +-+ *
| | |   | |  
* + + . + + *
| | |   | |  
* + + . + + *
| | |   | |  
* +-+ . + $ *
|       |    
+-*-*-*-* * +

Shortest solution (29 tiles):
* * *-*-* * *
    |   |    
* . + . + . *
    |   |    
* . + . + . *
    |   |    
* . + $-+ . *
    |        
* +-+ . +-+ *
  |     | |  
* +-+ . + + *
    |   | |  
* +-+ . + + *
  |     | |  
* +-+ . + $ *
    |   |    
+ * *-*-* * +

script finished running
script stopped.
For reference: If the programs are improved even more, it must be at least as good as that for the benchmark:
    *    *    *    *    *    *    *   14   13   12

    *   21   20   19   18   17   16   15    -   11

   23   22    -    -    -    -    -    -    -   10

   24    -    -    -    -    -    -    -    8    9

   25    -    1    2    3    4    5    6    7    -

   26    -    -    -    -    -    -    -   44   43

   27    -   51   50   49   48   47   46   45   42

   28    -    -    -    -    -    -    -   40   41

   29    -   33   34   35   36   37   38   39    *

   30   31   32    *    *    *    *    *    *    *
----------------------------------- Edit: Another good idea would be: Before you start to brute-force, calculate an estimation on how many frames and how many fields are required at least. For example for the benchmark puzzle it's (3 frames + 4 frames)*(math.min(rows, colums)-1) = 49 frames and sum over all rows i (min(black in row i, white in row i)) = 1*8 = 8. To measure partial solutions, just add 7 frames * (min(incompletely solved rows, incompletely solved columns) - 1) for minimum score, or #unused fields for minimum fields. Then when searching for solutions, look on how hard it will be to brute-force. If it might take very long, calculate an estimate and enqueue. First calculate the "easy" solutions which don't require too much brute-force. Now after you found some "easy" solutions, you can come back to the solutions requiring a lot of brute-force. You should be able to find the solution given above pretty fast. Now that was done: If you can only find solutions which take more fields and more frames than the currently best solution, then throw it away and don't brute-force at all. example:
Best attempt before brute-forcing:
*-*-*-*-*-*-*-*-* +
|               |
* . . . . . . . +-*
|                 |
*-+ . . . . . . . *
  |               |
*-+ A?A?A?A?A?A . *
|   ? ? ? ? ? ?   |
* . A?A?A?A?A?A-+-*
|   ? ? ? ? ? ?
*-+-A?A?A?A?A?A . *
    ? ? ? ? ? ?
* . A?A?A?A?A?A-+-*
    ? ? ? ? ? ?   |
*-+ A?A?A?A?A?A . *
|   ? ? ? ? ? ?   |
* . A?A?A?A?A?A-+-*
|   |   |   |
*-*-* * *-*-* * * +
This requires 29 turns at least, and ~70 fields. The solution found above requires 18 turns, and 51 fields. It is definitely impossible for this situation to get a better solution than the one above. -------------------------------------------
Found connections at region edges:
+++++++.
+.......
.......+
+.......
.......+
.aaaaa?+
+!aaaaa.
.??????+

Best attempt before brute-forcing:
A?A?A?A?A?A?A?*?*?*
? ? ? ? ? ? ? |   ?
A?A?A?A?A?A?A-+ . *
? |               ?
*-+ . . . . . . . *
?                 ?
* . . . . . . . +-*
?                 ?
*-+ . . . . . . . *
?                 ?
* . . . . . . . +-*
?               | ?
* . +-B?B?B?B?B?B?B
?   | ? ? ? ? ?   ?
*-+-+ B?B?B?B?B . *
?     ? ? ? ? ?   ?
* . +-B?B?B?B?B?B?B
?   | ? ? ? ? ? ?
*?*?*?B?B?B?B?B?B B
This should be detected as unsolvable. The reason is easy: Take one starting point. Now solve the top part. If you now continue, then you come across the other endpoint and didn't solve the lower part. Now take a starting point, and assume you could solve the lower part. You can't get to the top part afterwards without coming across the other endpoint. ------------------------------------
Trying row combination:
1111112.
2.......
.......4
4.......
.......2
.2111111
2111111.
.1111111
0 endpoints available.
If there are already two endpoints, it is safe to assume that every cell which has two forced neighbors is also a forced cell connected to both of them - otherwise it would create an additional endpoint, which is forbidden. In this case, the 1 at the lowest left would also become a forced cell this way. --------------------------------- Also: If two rows are completely disconnected, then finding the solution can be split in two parts. For example, in my solution for the benchmark puzzle, the top two rows are disconnected from the rest of the puzzle, so finding the solutions can be split as following: - solve the top part, use row 2, column 0 as an endpoint, use row 2, column 9 as an endpoint. at the same time: solve the bottom puzzle, use (3,0) and (3,9) as endpoints, allow two additional endpoints anywhere in the bottom part. - solve the top part using two endpoints, one of them being (2,0). at the same time, solve the bottom part using two endpoints, one of them must be (3,0). - solve the top part using two endpoints, one of them being (2,9). at the same time, solve the bottom part using two endpoints, one of them must be (3,9). - solve the top part by using a total of 4 endpoints, two of them are (2,0) and (2,9). solve the bottom part using (3,0) and (3,9) as endpoints. ----------------------------------------- another edit:
MEM_COLS = 0x020E3F64
MEM_ROWS = 0x020E3FA8

MEM_CELL_ROW1_COL1 = 0x020E03C4
MEM_rowoffset = 0x0140
MEM_coloffset = 0x14
MEM_valoffset = 0x1

function readpuzzle()
	local puzzle = {}
	local rows = memory.readbyte(MEM_ROWS)
	local cols = memory.readbyte(MEM_COLS)
	
	for r = 1, rows do
		puzzle[r] = {}
		for c = 1, cols do
			puzzle[r][c] =
				memory.readbyte(
						MEM_CELL_ROW1_COL1
					+	MEM_rowoffset * (r - 1)
					+	MEM_coloffset * (c - 1)
				)	- MEM_valoffset
		end
	end
	
	return puzzle
end
Editor, Player (44)
Joined: 7/11/2010
Posts: 1029
I think I found the bug, just testing at the moment. I'll let you know when it's fixed.
Found connections at region edges:
+++++++.
+.......
.......+
+.......
.......+
.aaaaa?+
+!aaaaa.
.??????+

Best attempt before brute-forcing:
A?A?A?A?A?A?A?*?*?*
? ? ? ? ? ? ? |   ?
A?A?A?A?A?A?A-+ . *
? |               ?
*-+ . . . . . . . *
?                 ?
* . . . . . . . +-*
?                 ?
*-+ . . . . . . . *
?                 ?
* . . . . . . . +-*
?               | ?
* . +-B?B?B?B?B?B?B
?   | ? ? ? ? ?   ?
*-+-+ B?B?B?B?B . *
?     ? ? ? ? ?   ?
* . +-B?B?B?B?B?B?B
?   | ? ? ? ? ? ?
*?*?*?B?B?B?B?B?B B
This should be detected as unsolvable. The reason is easy: Take one starting point. Now solve the top part. If you now continue, then you come across the other endpoint and didn't solve the lower part. Now take a starting point, and assume you could solve the lower part. You can't get to the top part afterwards without coming across the other endpoint.
Yeah, I noticed this rule too, and is probably the most useful rule for solving that I haven't implemented yet. I need to work out how to express it in Lua. EDIT: Yeah, it was a simple typo in the solver that caused it to disregard solutions that used the border exactly once, that caused us to end up with those suboptimal solutions. Fixed version of the program is up at the same URL.
Joined: 3/14/2008
Posts: 152
Location: United Kingdom
partyboy1a wrote:
another edit:
MEM_COLS = 0x020E3F64
MEM_ROWS = 0x020E3FA8

MEM_CELL_ROW1_COL1 = 0x020E03C4
MEM_rowoffset = 0x0140
MEM_coloffset = 0x14
MEM_valoffset = 0x1

function readpuzzle()
	local puzzle = {}
	local rows = memory.readbyte(MEM_ROWS)
	local cols = memory.readbyte(MEM_COLS)
	
	for r = 1, rows do
		puzzle[r] = {}
		for c = 1, cols do
			puzzle[r][c] =
				memory.readbyte(
						MEM_CELL_ROW1_COL1
					+	MEM_rowoffset * (r - 1)
					+	MEM_coloffset * (c - 1)
				)	- MEM_valoffset
		end
	end
	
	return puzzle
end
I take it this reads the puzzles from the game. I'll try it in a bit, what does it give for grey squares though since the addresses I found seemed to "remember" the last black or white even if the tile was grey. If this does work though I'll try to make a bot to do some testing with luck manipulation though I'm starting to think it may only be frame on which puzzles are solved, and the frame you originally enter puzzle mode (I edited the dsm of my wip to remove the random drawing between solves and it still synced, but adding in frames of delay before starting desyncs it, can't test times of solves easily like this though due to dragging down needing to be done on specific frames). In terms of tasing this makes the manipulation a massive/impossible task if every frame gives a different result as you would have to test waiting fastestsolution-50 frames after every single puzzle, giving a massively branching tree, and if we say the average drop over the entire puzzle mode is 3 lines then very roughly that would mean ~50^300=5x10^509 total routes (though certain routes would be cut off at a certain point if they could not be faster even with a 50 frame solution every time). My maths on that may be completely wrong though, so feel free (and try) to correct me. The 50 is from assuming an average solution will be 100 frames (and obviously the accuracy of this guess affects the above calculation alot). For reference, input of a successful drag down on the cancel button (the left/right movement is unnecessary):
|0|.............244 136 1|
|0|.............244 138 1|
|0|.............243 143 1|
|0|.............241 149 1|
|0|.............243 153 1|
|0|.............245 161 1|
|0|.............246 168 1|
|0|.............245 175 1|
Editor, Player (44)
Joined: 7/11/2010
Posts: 1029
Also check to see if changing the date on the DS changes the random seed. It does, for some games.