在游戲制作里黔牵,一般會(huì)存在大量的配置文件,比如說地圖的配置煤惩,NPC的配置嫉嘀,技能的配置,任務(wù)活動(dòng)的配置魄揉,
這些配置經(jīng)常是以 二維表的形式存在剪侮,我們的策劃喜歡強(qiáng)大的表格處理工具excel
這種配置,可以算得上是小型數(shù)據(jù)庫洛退,我曾見過超過10M的配置數(shù)據(jù)瓣俯,
面對(duì)這樣的配置類型红淡,我們有查詢的需求,比如說:
- 查詢當(dāng)前玩家所在地圖所有可用的跳轉(zhuǎn)點(diǎn)
- 查詢玩家當(dāng)前地圖上所有可交互的NPC降铸,將它們生成在玩家附近。
- 滿足當(dāng)前條件的所有可接任務(wù)的集合摇零。
- 獲取當(dāng)前條件下玩家可學(xué)習(xí)的技能集合推掸。
如果
我們面對(duì)非SQL系統(tǒng)的數(shù)據(jù)源,
我們需要在當(dāng)前的編程環(huán)境下驻仅,方便地表達(dá)查詢谅畅,
c#的解決辦法, linq, (其實(shí)我們可以在很多語言里實(shí)現(xiàn)類似的技術(shù), 不過這是另外一個(gè)題目了,stream API)
c# 對(duì)于任何數(shù)據(jù)類型噪服,如果實(shí)現(xiàn)了IEnumerable 接口毡泻,即視為可應(yīng)用linq查詢的數(shù)據(jù)源。
例: 查詢當(dāng)前玩家所在地圖所有可用的跳轉(zhuǎn)點(diǎn)
(假設(shè)可用跳轉(zhuǎn)點(diǎn)條件為粘优,當(dāng)前地圖仇味,等級(jí)要求,完成任務(wù)ID)
class Potal
{
int mapID;
int level;
int taskID;
...
};
class Potals : IEnumerable<Potal>
{
...
}
...
var validPotals = from potal in potals
where potal.mapID == player.map.ID &&
potal.level <= player.level &&
player.taskDone.Contain(potal.taskID);
對(duì)于不熟linq語法的讀者雹顺,我寫成另一種形式
var validPotals = potals.Where(potal =>
{
return
potal.mapID == player.map.ID &&
potal.level <= player.level &&
player.taskDone.Contain(potal.taskID);
});
翻譯成最平凡的語法是丹墨,
List<Potal> validPotals1 = new List<Potal>();
foreach (var potal in potals)
{
if(potal.mapID == player.map.ID &&
potal.level <= player.level &&
player.taskDone.Contain(potal.taskID))
{
validPotals1.Add(potal);
}
}
在這樣簡單的例子里, linq并不能表達(dá)它優(yōu)勢(shì),但畢竟, linq給我們帶來了強(qiáng)大的表達(dá)能力嬉愧,我們初步實(shí)現(xiàn)了贩挣,“告訴計(jì)算機(jī)我們需要什么,而不是怎樣去做"没酣,
在計(jì)算機(jī)科學(xué)里王财,這樣的編程范式叫做”邏輯式編程“,邏輯式編程能做的遠(yuǎn)不止數(shù)據(jù)庫查詢(相對(duì)于大家對(duì)SQL這種特定語言的印象)裕便。
邏輯式編程語言(prolog)里绒净,只有三類表達(dá)式,
- 事實(shí)(Facts), 它是數(shù)據(jù)集闪金,可以理解為各種數(shù)據(jù)源疯溺,數(shù)據(jù)表,
- 規(guī)則(Rules): 對(duì)應(yīng)的是 合一規(guī)則哎垦, 可以理解成數(shù)據(jù)源的約束囱嫩,
- 查詢(Queries): 問題求解
我們都學(xué)過一些基礎(chǔ)邏輯, 一個(gè)有名的例子(三段論):
一切人都會(huì)死,
蘇格拉底是人漏设,
所以蘇格拉底會(huì)死墨闲,
寫成prolog程序
human(Socrates)//事實(shí):
motal(X) :- human(X)//規(guī)則:
?- motal(Socrates)//查詢
>> yes
我們推導(dǎo)出 蘇格拉底 確實(shí)會(huì)死,
好吧郑口,我們強(qiáng)來鸳碧,在c# 表達(dá)如此邏輯
class Mortal { }
class Human : Mortal { }//規(guī)則盾鳞,人類是會(huì)死生物
static void Main(string[] args)
{
var Socrates = new Human(); //事實(shí)
if(Socrates is Mortal) //查詢
{
Console.WriteLine("yes!");
}
}
(好像我們發(fā)現(xiàn)了點(diǎn)什么...關(guān)于類型和邏輯的關(guān)系是個(gè)艱深的話題 )
以下,我做一個(gè)極為簡單的邏輯系統(tǒng)瞻离,在這系統(tǒng)里完成以上的邏輯式查詢, 為了易于表達(dá)腾仅,測(cè)試?yán)镂覀冎豢紤]一元的情況(arity), 比如說Query1(將只查詢一元屬性的Fact)
//lxf0525@gmail.com
class KnowlegeBase
{
class Entity
{
public string name = "";
}
class Atom : Entity { }//原子enity
class Variable : Entity { }//變量 enity, 將作為合一的名稱
class Fact //事實(shí)
{
public static List<Fact> facts = new List<Fact>();
//加入一個(gè)Fact(一元)
public static Fact newFact1(string tag, string atomName)
{
Fact f = new Fact();
f.tag = tag;
f.ents.Add(new Atom() { name = atomName });
facts.Add(f);
return f;
}
public string tag = "";
public List<Entity> ents = new List<Entity>();
public Atom getFirstAtom()
{
return ents.First() as Atom;
}
public static IEnumerable<Fact> getFact(string tag)
{
return facts.Where(f => f.tag == tag);
}
}
class Rule//規(guī)則
{
public Fact implication;
public List<Fact> prerequisite = new List<Fact>();
public static List<Rule> Rules = new List<Rule>();
public static Rule newRule1(string tagImplication, string tagPrerequisite)
{
Fact f = new Fact();
f.tag = tagImplication;
f.ents = new List<Entity>() { new Variable() { name = "X"}};
Fact f1 = new Fact();
f1.tag = tagPrerequisite;
f1.ents = new List<Entity>() { new Variable() { name = "X" } };
Rule r = new Rule();
r.implication = f;
r.prerequisite.Add(f1);
Rules.Add(r);
return r;
}
public static IEnumerable<Rule> getRule(string implicationTag)
{
return Rules.Where(r => r.implication.tag == implicationTag);
}
}
class Query //查詢
{
//1元Fact的查詢
public static IEnumerable<Atom> Query1(string factTag, string atomName)
{
//基本事實(shí)的查詢
var facts = Fact.getFact(factTag).Where(f => f.getFirstAtom().name == atomName);
foreach(var f in facts)
{
yield return f.getFirstAtom();
}
//規(guī)則查詢,
foreach(var r in Rule.getRule(factTag))
{
foreach(var f in r.prerequisite)
{
foreach(var a in Query1(f.tag, atomName) )
{
yield return a;
}
}
}
}
}
static void Main(string[] args)
{
Fact.newFact1("Human", "Socrates");
Rule.newRule1("Mortal", "Human");
Console.WriteLine(Query.Query1("Mortal", "Socrates").Count() > 0? yes : no);
}
}
////
// >> yes
可以看到套利,這樣小的系統(tǒng)通過查詢的方式推励,確實(shí)證明了 ”蘇格拉底必死"這一命題。