我正在尝试制作一个解决日本益智游戏“河流智商测试”的程序,我知道,我可以只查找解决方案,但这不会很有趣,现在就教育了吗? :)
以下是游戏的目标:
使用木筏,用户可以将人们运送过河,用户必须将所有人从左侧传送到右侧。每次使用木筏时,它都停留在另一侧,直到那边的人再次将它引导到另一侧以吸引更多的人。
左侧有以下人员开始:
以下是类的层次结构:
必须遵守以下规则:
我需要完成的是:
这是我目前的代码:
class Program
{
Side _leftSide = new Side(Side.RL_Side.RL_LeftSide);
Side _rightSide = new Side(Side.RL_Side.RL_RightSide);
Raft _myRaft = new Raft();
static void Main(string[] args)
{
// TODO: put systematic trial-and-error solving logic here
// TODO: make sure that successful solution is printed to console
Console.ReadLine();
}
}
public class PassengerList : List<Passenger>
{
public bool CheckRulesObeyed()
{
bool isPoliceman = isPresent<Policeman>();
bool isPrisoner = isPresent<Prisoner>();
bool isFather = isPresent<Father>();
bool isSon = isPresent<Son>();
bool isMother = isPresent<Mother>();
bool isDaughter = isPresent<Daughter>();
// ----------------------------------------------
bool isPrisoner_NonPoliceman = (isPrisoner && (isFather || isMother || isDaughter || isSon));
bool isPrisonerRuleViolated = (!(isPoliceman && isPrisoner) && isPrisoner_NonPoliceman);
bool isDaughterRuleViolated = ((isFather && isDaughter) && !isMother);
bool isSonRuleViolated = ((isMother && isSon) && !isFather);
bool AreAllRulesObeyed = !(isPrisonerRuleViolated && isDaughterRuleViolated && isSonRuleViolated);
return AreAllRulesObeyed;
}
private bool isPresent<T>() where T: Passenger
{
foreach (Passenger p in this)
{
if (p is T)
return true;
}
return false;
}
}
public class Side
{
public enum RL_Side
{
RL_RightSide,
RL_LeftSide
}
public RL_Side _whichSide;
public PassengerList _myPeople;
public Side(RL_Side side)
{
_whichSide = side;
_myPeople = new PassengerList();
// left side starts with all the people
if (_whichSide == RL_Side.RL_LeftSide)
{
_myPeople.Add(new Prisoner());
_myPeople.Add(new Policeman());
_myPeople.Add(new Father());
_myPeople.Add(new Son());
_myPeople.Add(new Son());
_myPeople.Add(new Mother());
_myPeople.Add(new Daughter());
_myPeople.Add(new Daughter());
}
}
public bool didEveryoneMakeItToRightSide()
{
if (_whichSide == RL_Side.RL_RightSide)
{
// TODO: implement logic that checks and returns if everyone is on the right side.
}
return false;
}
}
public class Raft
{
public Side _mySide;
public PassengerList _myPassengers;
public void ChangeSides(Side Destination)
{
_mySide = Destination;
}
public bool LoadRaft(Pilot myPilot, Passenger myPassenger)
{
bool areRulesObeyed = true;
_myPassengers.Add(myPilot);
_myPassengers.Add(myPassenger);
areRulesObeyed = _myPassengers.CheckRulesObeyed();
if (areRulesObeyed == false)
{
UnloadRaft();
}
return areRulesObeyed;
}
public void UnloadRaft()
{
foreach (Passenger p in _myPassengers)
{
_mySide._myPeople.Add(p);
_myPassengers.Remove(p);
}
}
}
答案 0 :(得分:4)
我认为你从未学过PROLOG。这些问题在PROLOG中是经典的,更重要的是PROLOG只处理问题的本质。当我在标题中看到逻辑和谜题时,显然你需要一种逻辑语言。我知道你要求C#,但这不是OO问题,因为你说这是一个逻辑问题。
见Prolog Programming in Depth第229页第8.3节。传教士与传教士 请注意,解决方案小于问题中的所有代码。不要误会我的意思,很多年前我在同一条船上,双关语。
我认识的一些最优秀的程序员在这样的问题上工作不是为了解决方案,而是因为他们自己解决这些问题,他们知道他们会学到一些重要的东西,他们可以使用后者。花几个月的时间来了解PROLOG如何解决这个问题,你会比给你建议的人好多了。如果你不理解递归以及AI如何解决问题,那么当你得到解决方案时,你将大部分时间。
修改
C#是否无法解决这类问题?
PROLOG有一个内置的inference engine和back-chaining,这是根据规则找到解决方案的工作。您可以从头开始创建一个,这比解决您的初始问题更难,但是在John C#,C#Prolog中有一个PROLOG的开源实现。虽然您可以查看源代码以了解PROLOG的工作原理,但代码经过大量优化,因此除非您首先了解PROLOG,否则不易理解。
如果您了解F#或函数式语言How to implement a prolog interpreter in a purely functional language?可能有所帮助。
基本上问题归结为创建一组规则然后尝试组合规则,直到获得满足所有规则的结果。
从这些关键词和短语开始,在这里搜索互联网和问题。
统
句法统一
BACK-链接
推理引擎
prolog如何工作
答案 1 :(得分:0)
您可以使用支持递归的任何语言相对轻松地执行此操作,
使用Backtracking,一种简单的算法/技术。
举例来说:
你有问题状态(每边的人)
你有一个功能,列举所有可能的交叉点
从那个州,并尝试每一个。
如果交叉点正常,则会将新状态添加到历史记录中
并从新的国家召唤自己
当它返回时,它从历史中删除状态
并尝试下一个十字路口
当它用完交叉点时,它会返回其调用者。
你需要历史,因为唯一的终端状态是目标
否则你可能会进入循环:
A组穿过一条路,然后返回,再次穿过,返回等等
或者A单向交叉,B交叉,B返回,A返回等等。
(抱歉,我无法弄清楚如何让代码格式化程序在这里工作。)