首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >代码高尔夫:河内塔楼

代码高尔夫:河内塔楼
EN

Stack Overflow用户
提问于 2010-12-03 16:37:09
回答 3查看 2.2K关注 0票数 17

规则

河内的塔是一个谜,如果你对它不太熟悉,下面是它的工作原理:

比赛场地由3根棒和x个圆盘组成,每一个盘都比前一个大。使用这些规则,可以将磁盘放在棒上。

  • 一次只能移动一个磁盘,而且它必须移动在另一个棒的顶部。
  • 圆盘必须从棒子的顶部取下来。
  • 一个磁盘可以移动到某个地方,只有当目标杆上的最上面的磁盘大于要移动的磁盘时,才能移动磁盘。

最后-像这样启动

  • 一个有x个圆盘的棒子,所以最大的在底部,最小的在顶部。
  • 空棒
  • 空棒

游戏的目标是在另一个杆上移动原始的磁盘“堆栈”,也就是把所有的磁盘放在另一个棒上,所以(再次)最大的在底部,最小的在顶部。

实现

您的目标将是用您选择的编程语言编写一个程序,该程序需要输入(如下所述)并输出解决该位置所需的步骤。

像往常一样,尽量缩短时间。

输入

一个示例输入:

代码语言:javascript
运行
复制
4-3,7-6-5,2-1

输入是一个字符串,由三个部分组成,用逗号分隔。这些部件是三个杆中每一个上的磁盘列表。它们也是分开的,这一次用连字符(- ),每个子部分是一个数字,数字越大,磁盘就越大。

因此-对于上面的输入,这将是一个可视化的表示:

代码语言:javascript
运行
复制
       .               .               .
       |          =====|=====          |
    ===|===      ======|======        =|=
   ====|====    =======|=======      ==|==

     ROD 1           ROD 2           ROD 3

输出

正如你在上面的表示中所看到的--输入的最左边的部分是第一杆,中间是第二杆,最后一个是杆数3。

程序的输出应该如下所示:

代码语言:javascript
运行
复制
12,23,31,12,23,13

用逗号分隔的数字列表,定义了应该取磁盘的杆和应该放盘的棒。只有3根棒,所以只有6种可能的组合(因为磁盘必须移动到另一根棒上,而不是同一条):

代码语言:javascript
运行
复制
12
13
21
23
31
32

备注

输入不需要描述一个“原始”状态的字段--它可以被中间解决。

您的程序不能产生空输出。如果输入处于原始状态,只需将磁盘放到另一个棒上即可。

输入可以有一个空棒,如下所示:

代码语言:javascript
运行
复制
2-1,3,
,,1
4-3,,2-1

如果输入不在这种格式中,您的程序可能会产生未定义的行为。因此,如果输入无效(就像较小的磁盘上的更大的磁盘,丢失的磁盘,不可解的),则可以这样做。valid.输入始终是

确保解决方案尽可能快(尽可能小的转弯)--也就是说,不要在“12,21,12”之前浪费时间.

测试

所以,我为你准备了这个小闪光灯,你可以用它来测试你的程序是否产生了一个很好的解决方案,而不用写下来什么的。

这里是:河内AlgoTest (等待它加载,然后刷新-- Dead链接:\\)

要使用它,请将输入粘贴到程序的输入字段,并将程序生成的输出粘贴到PROCESS字段。它将运行一个模拟,以你也可以改变的速度,用一个可视化的表示,打印出在底部的任何错误。

希望能帮上忙。

EN

回答 3

Stack Overflow用户

发布于 2010-12-04 11:16:27

这里是10的入门版,在Scala中,修改了几次。我不知道有什么问题,我也没有其他办法进一步减少行动

作为Scala脚本运行。

其中的部分相当优雅(IMO),但其他比特是一个丑陋的黑客。

最短的代码(但不是最优的移动),跟踪磁盘的位置,而不是棒上的磁盘列表(从Perl解决方案中无耻地窃取主意)。

代码语言:javascript
运行
复制
 val r=args(0).split(",",-1);var d=Map{{for(q<-0 to 2 if""!=r(q);n<-r(q).split('-').map{_.toInt})yield(n,q+1)}:_*};val n=d.max._1;var m="";def s(f:Int,t:Int,n:Int):Unit=if(n!=0&&f!=t){s(f,6-f-t,n-1);d=d+(n->t);m=m+","+f+t;s(6-f-t,t,n-1)};for(c<- 2 to n)s(d(1),d(c),c-1);if(m=="")s(d(1),d(1)%3+1,n);println(m.tail.replaceAll("(.),?\\1",""))

拼图是从命令行中提取的。

338字节不太简陋,因为这是一种静态类型的语言,并且仍然相对可读的(如果您用换行符替换;)

可读的版本如下(有更多的最佳动作)

代码语言:javascript
运行
复制
val rods = args(0).split(",", -1);
var diskLocation = Map{
  {
    for (rod <-0 to 2 if rods(rod).nonEmpty;
         n <-rods(rod).split('-').map{_.toInt})
      yield(n, rod + 1)
  }:_*
}

val nDisks = diskLocation.max._1

var moves = ""

def moveTower(start:Int, end:Int, n:Int):Unit = 
  if (n != 0) {
    val other = 6 - start - end
    moveTower(start, other, n - 1)
    moveDisk(n, end)
    moveTower(other, end, n - 1)
  }

def moveDisk(n:Int, end:Int) = {
  moves = moves + "," + diskLocation(n) + end
  diskLocation = diskLocation.updated(n, end);
}

for (c <- 2 to nDisks) {
  var firstLocation = diskLocation(1)
  var nextLocation = diskLocation(c)
  if (firstLocation != nextLocation) {
    if (c != nDisks) {
      val diskAfter = diskLocation(c + 1)
      if (diskAfter != firstLocation && diskAfter != nextLocation) {
        moveDisk(c, diskAfter)
        nextLocation = diskAfter
      }
    }
    moveTower(diskLocation(1), diskLocation(c), c - 1);
  }
}

if (moves == "")
  moveTower(diskLocation(1), diskLocation(1)%3 + 1, nDisks)

println(moves.tail.replaceAll("(.),?\\1",""))
票数 4
EN

Stack Overflow用户

发布于 2010-12-07 16:37:24

Perl 241焦

当然不是最有效的方法,但它有效。

更新,以抑制最后逗号。

代码语言:javascript
运行
复制
map{map$g[$_]=$i|0,/\d/g;$i++}split$,=',',<>;shift@g;@G=(0)x@g;@u=(1)x10;while(!$G[@g]){$G="@G";$_="@g";$i=0;$j=$G[0]+$u[0];while($j>2||$j<0){$u[$i++]*=-1;$j=$u[$i]+$G[$i]}$r=1+$G[$i].$j+1;$G[$i]=$j;$p=1if/$G/;push@o,$r if$p&&$i++<@g}print@o

白空间也是如此:

代码语言:javascript
运行
复制
map{
  map $g[$_]=$i|0, /\d/g;
  $i++
}split$,=',',<>;
shift@g;
@G=(0)x@g;
@u=(1)x10;
while(!$G[@g]){
  $G="@G";
  $_="@g";
  $i=0;
  $j=$G[0]+$u[0];
  while($j>2||$j<0){
    $u[$i++]*=-1;
    $j=$u[$i]+$G[$i]
  }
  $r=1+$G[$i].$j+1;
  $G[$i]=$j;
  $p=1if/$G/;
  push@o,$r if$p&&$i++<@g
}
print@o

用法:

代码语言:javascript
运行
复制
echo 5-2,3-1,4 | perl hanoi.pl

输出:

21,23,12,23,12,32,21,23,12,23,12,32,21,32,12,23,21,32,21,32,12,23,12,32,21,23,12,23,21,32,21,32,12,23,21,32,21,32,12,23,12,32,21,23,12,23,12,32,21,32,12,23,21,32,21,23,12,23,12,32,21,23,12,23,21,32,21,32,12,23,21,32,21,32,12,23,12,32,21,23,12,23,21,32,21,32,12,23,21,32,21,23,12,23,12,32,21,23,12,23,12,32,21,32,12,23,21,32,21,23,12,23,12,32,21,23,12,23,12,32,21,32,12,23,21,32,21,32,12,23,12,32,21,23,12,23,21,32,21,32,12,23,21,32,21,23,12,23,12,32,21,23,12,23,12,32,21,32,12,23,21,32,21,23,12,23,12,32,21,23,12,23

票数 1
EN

Stack Overflow用户

发布于 2010-12-04 19:33:09

试图在Lua上实现来自维基百科的迭代解决方案,但是它并不真正有效,但是我花在它上的时间已经很长了,所以我希望这能激励人们去适应它。它确实很好地解析了所有东西,包括空列。额外的好:它可以很好地打印堆栈,就像在问题中的视觉表现一样。

代码语言:javascript
运行
复制
-- Input "rod1,rod2,rod3" where rod? = a - seperated list of numbers, representing the disks.
p,q,r=io.read():match'([^,]*),([^,]*),([^,]*)'
print(p,q,r)
i=table.insert
u=unpack
function gen(t)
    return function(v)i(t,tonumber(v)) end
end

function basic(t,n) 
    for k,v in pairs(t) do
        print(k,"----")
        for kk,vv in pairs(v) do print("\t",kk,vv) end
    end
    print'================'
end
function pretty(t,n)
    local out={}
    for k=1,n do out[k]={} end
    for k=1,n do                -- K is each row
        local line=out[k]
        for l=1,3 do            -- L is each rod
            local d=t[l][k]
            if d~=1e9 then -- TODO Check if metahack necesarry
                line[#line+1]=(" "):rep(n-d+1)
                line[#line+1]=("="):rep(d)
                line[#line+1]="|"
                line[#line+1]=("="):rep(d)
                line[#line+1]=(" "):rep(n-d+1)
                line[#line+1]=" "
            else
                line[#line+1]=(" "):rep(2*n+4)
            end
        end
        out[k]=table.concat(line)
    end
    for k=n,1,-1 do
        io.write(out[k],"\n")
    end
end
function T(f,...)
    w=0
    for k=1,3 do
        l=({...})[k]
        w=#l==0 and w or f(w,u(l))
    end
    return w
end

Stat=pretty
t={{},{},{}} --rods 1 - 3, discs ordered 1 = bottom
for k,v in pairs{p,q,r}do -- loop over strings
    v:gsub('%d+',gen(t[k])) -- add decimal to rod
end
n=T(math.max,t[1],t[2],t[3]) -- Biggest disc = number of discs
--for k=1,3 do c=1*t[k][1] if n==c then A=k elseif m==c then C=k else B=k end end -- Rod where the biggest disc is (A)
for k=1,3 do setmetatable(t[k],{__index = function() return 1e9 end}) c=t[k] if c[#c]==1 then one=k end end -- locate smallest disc, and set index for nonexistant discs to 1e9
-- Locate second biggest disc (B), smallest stack = C -> move C to B
-- Algorithm:
-- uneven : move to the left, even: move to the right
-- move smallest, then move non-smallest.
-- repeat until done
--
-- For an even number of disks:
--
--     * make the legal move between pegs A and B
--     * make the legal move between pegs A and C
--     * make the legal move between pegs B and C
--     * repeat until complete
--
-- For an odd number of disks:
--
--     * make the legal move between pegs A and C
--     * make the legal move between pegs A and B
--     * make the legal move between pegs B and C
--     * repeat until complete
--
-- In each case, a total of 2n-1 moves are made.
d={{2,3,1},{3,1,2}}
s=d[math.fmod(n,2)+1] -- sense of movement -1 left (uneven # of discs), 1 right (even # of discs)
Stat(t,n)
for qqq=1,10 do
    -- move smallest
    d=s[one]
    print(one,d)
    if #t[d]==0 then print("skip rod",d,"next rod",s[d]) d=s[d] end-- if rod is empty, move to next in same direction
    table.insert(t[d],table.remove(t[one])) --TODO Problem
    print("Moved",one,"to",d)
    one=d -- track the small disc
    Stat(t,n)
    if #t[d]==n then break end -- destination stack reached number of discs, break off.
    -- find next valid move (compare the two non-previous-destination rod) to see which has the smallest disc, move disc to other rod.
    z=0
    for k=1,3 do
        print("-- k="..k)
        if k~=one then
            if z>0 then
                if t[k][#t[k]] > t[z][#t[z]] then   -- disc at rod z (source) is smaller than at k (destination)
                    d=k                                 -- destination = k 
                    print("-- t["..k.."]>t["..z.."], d="..d..", z="..z)
                else                                    -- disc at rod z (source) is bigger than at k (destination
                    d,z=z,k                             -- switch destination and source, so d will be z, and z will be the current rod
                    print("-- t["..k.."]<t["..z.."], d="..d..", z="..z)
                end
            else -- first of rods to compare
                z=k
                print("-- First rod to compare z="..z)
            end
        else
            print("-- disc one at this location, skipping",k)
        end
    end
    print("Will move from",z,"to",d)
    table.insert(t[d],table.remove(t[z]))
    Stat(t,n)
    if #t[d]==n then break end -- destination stack reached number of discs, break off.
end
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4347718

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档