2014-2020?
平面上有很多冰塊跟火團
每次可以把一個冰塊往縱向或橫向推,冰塊會一直往同個方向移動到
- 碰到障礙物停下來,或
- 碰到火團然後兩者都消失 (金色冰塊碰到火團不會消失,會繼續往前進)
- 消冰器 (recycler) 然後掉進去消失
把所有火團滅掉就完成
網頁版,可以當做是懶人包:氷塔 ―魔法使いの挑戦―
If not otherwise mentioned, the game spec is according to the original game, 氷塔.
maximum map size = 20 * 14 (18 * 12 if excluding borders); ice count has a hard limit 200 in source code; all indices can be stored in short int
(2 bytes long).
A level/solver can be classified with the max index it contains/supports, with increasing complexity:
Index | Item + repr. | Remarks |
---|---|---|
N/A | wall # |
|
- | ice % |
A regular one. |
1 | fire * |
|
2 | recycler - |
When a regular ice block moves to this cell, it is destroyed. |
3 | golden ice $ |
A golden ice is permanent in a level. There is no way to destroy one. |
(4) | magician @ |
Since here, the magician's reachability is considered |
4 | arrows v^<> |
Magician/ices are allowed to co-exist on the same spot |
5 | dispenser + |
dispense ice blocks randomly to four directions, if possible |
Note: Despite seemingly complicated, "recyclers only" stages are usually easier for brute-forcing.
Considering only 1. or additionally 2. may be a good practice on various space searching techniques (like sokoban).
For example, W-21 is a good demonstration, that some simple configurations lead to hard enough puzzles at least for humans:
Can you spot out a 21-step solution? See one in this sample output from my solver. Note that it requires a correct implementation of reachability-checking to admit a legitimate solution.
A straightforward solver typically considers 1. & 3. only; The aim here is to consider 1. ~ (4). and it's far more challenging than before.
We can call the above simple configurations static. Adding some arrows & dispensers, the game becomes dynamic and is dramatically complicated.
Here is a popular construction that makes use of arrows: Some arrows may form a cycle which traps everything entering it. A tight arrow cycle forms a n-barrier, requiring (n-1) ice blocks inserted for the magician to pass through. Otherwise, the magician will stuck forever.
For static configurations, this is the only possible transition
the region it can move to (w/o any side-effects) can be seen as a contiguous partition over total space, which is invalidated when any ice block is moved
how to define "elsewhere" is hard
heuristics? potential method?
dead state detection: prune states where
at least one fire is of no reachable ice blocks (?)
(movable ices > fire count) && no movable golden ices.
The following cases are considered non-movable ("dead-position" detection):
(not knowing if it's correct): (non-edge ice blocks > non-edge fire count) && no non-edge golden ices
observation: (# of ice blocks that is at edge position) is monotonic?
block reachability?
bipartite matching?
Full state = Board configuration (static) + {initial, incremental} state
Board configuration:
walls are special: ice blocks is stopped one cell off instead of onto them.
When exploring possible transitions, a shared BoardView (i.e., a full sized map to put objects on; Possibly one in each stack) is faster, but storing it in each state is too expensive. Without pruning, a 11-step stage may grow to 109 states (OG-13):
Initial state:
Incremental state (should be as tiny as possible):
old pos. is only for going back to parent state
→ ~ 24 bytes so far
Q: How to compute the map from an incremental state?
From scratch: Use configuration + initial state to populate the view. Walk until root state, recording states along the way and apply accordingly.
A state to another: Go backwardly to their LCA (knowing their depths is convenient) and then go forwardly to the other state. ref.
Q: How to store/update 2D map efficiently?
Preprocessing: One can pre-calculate all blocks' destinations for all directions as if only static obstacles are present. When a dynamic block is added/removed, only the corresponding column/row needs to be updated.
Q: Is there anything missing?
Note that a recycler/dispenser is not purely an "obstacle". An ice block may happen to overlap on top of it for a brief period (refer to the code for details). As per the spec, golden ices are not eliminated by recyclers – which simply pass through them. Even a naive approach needs to handle this, since a golden ice may stop on top of it upon stopping by a wall, e.g.,
None of official levels has this edge case AFAIK, though. Verification required: Is the above block pushable vertically afterwards?
Some sketch:
Iterative-deepening DFS: performs poorly since game graphs are tend to be cycle-rich (?). To preserve optimality, a transition table has to remember the depth it last visits and do relaxation… but the information has been forgotten then. If we try to memoize, this is essentially BFS, but we would have memory issues soon!
See the following levels that surely require heuristics.
OG: https://www.youtube.com/watch?v=jVoDiq131I4
TODO…
四個官方認可的關卡集:
Solutions: https://www.youtube.com/watch?v=RXHTMalW9lE
Chi-Feng: https://www.youtube.com/channel/UCjD7AdR1BW_NdVO3NHdqzjQ/discussion
(Naive) solver by Chi-Feng: mainly BFS + transition table
https://drive.google.com/file/d/106G1ffVkFVGpo8gPSeggq4N148I4TGJK/view
Modified by me:
https://gist.github.com/andy0130tw/fed21b0d1c8298098470bf34db50153f
王兆成: https://www.youtube.com/channel/UCnP6EicvzKWkLx1DC-v0utA
《冰塔攻略總論》:https://drive.google.com/file/d/1zjFQlsSoPrv219z_92cxMwSvWpHl-R5q/view
http://gameschool.cc/user/gorck820/#!mywork/forumTopic
http://web.archive.org/web/20161128090314/http://milkpot.sakura.ne.jp/icetower/index.html
http://sokobano.de/wiki/index.php?title=Solver
For collaborations, contact @qbane at Telegram.