野人与修道士问题的Ruby实现

问题描述:
河左岸有三个修道士,三个野人和一条船,假定船最多只能运两个人,且任何岸边的野人数目不得超过修道士,否则修道士就会被野人吃掉。
如何才能把修道士和野人都运到右岸?


Savage.rb


SAVAGE    = 0
BOANERGES = 1
DEEP      = 5

#记录状态
class Status
 @@StatusList = Array.new
 @@Pos = -1
 
  attr_writer :nSavage          #岸边野人的数量,全部到对岸为0
  attr_writer :nBoanerges       #岸边传教士的数量,全部到对岸为0
  attr_writer :nSide            #船的位置,在此岸为-1,对岸为1
  attr_writer :nMoveSavage      #渡河的野人的数量,用于递归时记录操作状态
  attr_writer :nMoveBoanerges   #渡河的传教士的数量,用于递归时记录操作状态 

  attr_reader :nSavage          
  attr_reader :nBoanerges       
  attr_reader :nSide            
  attr_reader :nMoveSavage      
  attr_reader :nMoveBoanerges   
 
  def initialize()
   @nSavage        =  3
   @nBoanerges     =  3
   @nSide          = -1
   @nMoveSavage    =  0
   @nMoveBoanerges =  0
 end
 
  def Status.getList()
   return @@StatusList
 end
 
  def Status.getPos()
   return @@Pos
 end
 
  def Status.addStatus(stat)
   @@StatusList.push(stat)
   @@Pos += 1
 end
 
 def Status.delStatus()
  @@StatusList.pop()
  @@Pos -= 1
 end
end

class Ship
 def Ship.hasNextStep(stat)
  store = [[],[],[],[],[]]
  
  if stat.nSide == -1 then
   store[0][SAVAGE]    = 2
      store[0][BOANERGES] = 0
      store[1][SAVAGE]    = 1
      store[1][BOANERGES] = 1
      store[2][SAVAGE]    = 0
      store[2][BOANERGES] = 2
     store[3][SAVAGE]    = 1
      store[3][BOANERGES] = 0
      store[4][SAVAGE]    = 0
     store[4][BOANERGES] = 1
  elsif stat.nSide == 1
      store[0][SAVAGE]    = 0
      store[0][BOANERGES] = 1
      store[1][SAVAGE]    = 1
      store[1][BOANERGES] = 0
      store[2][SAVAGE]    = 0
      store[2][BOANERGES] = 2
      store[3][SAVAGE]    = 1
      store[3][BOANERGES] = 1
      store[4][SAVAGE]    = 2
      store[4][BOANERGES] = 0  
  end

  iStart = 0
    if stat.nMoveSavage == 0 && stat.nMoveBoanerges == 0
     iStart = 0
    else
     for iStart in 0...DEEP
       puts iStart
    if stat.nMoveSavage == store[iStart][SAVAGE] && stat.nMoveBoanerges == store[iStart][BOANERGES]
         break
        end
      end
      iStart += 1
  end
   
  if (iStart < DEEP)
   i = 0
   for i in iStart...DEEP
    nSideSavage      = stat.nSavage + stat.nSide * store[i][SAVAGE]
        nSideBoanerges   = stat.nBoanerges + stat.nSide * store[i][BOANERGES]
        nBesideSavage    = 3 - nSideSavage
        nBesideBoanerges = 3 - nSideBoanerges

        #传教士数量大于等于野人或为零
        if ((nSideSavage   <= nSideBoanerges   || nSideBoanerges   == 0) &&
            (nBesideSavage <= nBesideBoanerges || nBesideBoanerges == 0) &&
             nSideSavage   >= 0 && nSideBoanerges >= 0 && nBesideSavage >= 0 && nBesideBoanerges >= 0) then
         #如果本此解等于上次,放弃
          if Status.getPos > 0
           if (Status.getList()[Status.getPos - 1].nMoveBoanerges == store[i][BOANERGES] &&
                Status.getList()[Status.getPos - 1].nMoveSavage    == store[i][SAVAGE])
               next
            end
          end
          break
        end
   end
   
   if i < DEEP
     stat.nMoveSavage    = store[i][SAVAGE]
        stat.nMoveBoanerges = store[i][BOANERGES]
        return true
      end
    end

    return false;  
 end
 
 #递归函数
 def Ship.find(stat)
   if hasNextStep(stat)
     pNew = Status.new
      pNew.nSavage        = stat.nSavage + stat.nMoveSavage * stat.nSide
      pNew.nBoanerges     = stat.nBoanerges + stat.nMoveBoanerges * stat.nSide
      pNew.nSide          = stat.nSide * -1
      pNew.nMoveSavage    = 0
      pNew.nMoveBoanerges = 0
      Status.addStatus(pNew)
     
      if pNew.nSavage == 0 && pNew.nBoanerges == 0
        Status.delStatus()
       return true
      end
      return find(pNew)
    else
      if Status.getPos == 0
       return false
      end
      Status.delStatus()

      return find(Status.getList()[Status.getPos])
    end
    return true
 end
end

initStat = Status.new
Status.addStatus(initStat)
if (Ship.find(initStat))
 puts "渡河过程如下:"
 Status.getList().each do |stat|
  print "下次渡河方向:", (stat.nSide == -1) ? "-->" : "<--", " 人数:野人", stat.nMoveSavage, " 传教士", stat.nMoveBoanerges, " 当前此岸野人数:", stat.nSavage, " 传教士数:", stat.nBoanerges, "/n"
 end
else
 puts "此题无解"
end
print "Press ENTER to return."
$stdin.gets

你可能感兴趣的:(野人与修道士问题的Ruby实现)