相信很多“牛人”都被一些宅男學弟問過這個問題:學長,我作為一個初學程序的菜鳥,要怎么樣才能提交自己的編程水平,變成牛人呢?
說實話,這個問題深奧地我有點回答不上來,無外乎只能告訴他“多讀”“多寫”“搞好數學和算法,練內功”“用好設計模式”“看《編程之美》”等等之類的空話套話。后來剃刀阿遠給出了一個答案讓我深受啟迪,他說:就一句話——多寫給人用的代碼。
這句話第一次聽上去也許覺得有點裝逼,實則不然,我非常認同這個觀點。
好吧,宅男學弟又開始問了:學長,什么樣的代碼才是給人用的代碼?畢竟我一個菜鳥我又不是騰訊不能彈窗口邀請別人來用,別人為什么要用一個菜鳥的代碼呢?
這個問題相對就更非常具體了,我個人認為,有實用價值同時又讓人覺得親切有趣的程序就可以了。
例如,Dota是一款80后程序猿耳熟能詳的游戲,尤其是還沒走出大學校門的挨踢宅男的最愛。毫無疑問,如果我們以Dota作為突破點,只要idea有意思、跟Dota緊密相關,就算是菜鳥寫的程序也能在學校BBS里被大家爭相傳閱。
本文就以“統計Dota玩什么英雄最容易拿MVP”為例,做一次拋磚引玉。文末我們可以討論更多關於Dota輔助程序的idea。
11對戰平台是最近流行的Dota平台,與其他對戰平台不同的是,11有海量的統計數據。對於每一個玩家,都有最詳細的統計,細到包括他所擅長的英雄、歷史上用哪個英雄做了哪些事、平均某個英雄出場殺敵數、甚至細到該玩家歷史上一共拿了多少個Double Kill都有記錄。
本文僅僅示例如何統計MVP而已,相對於11對戰平台的數據寶庫來說,可謂是“弱水三千,只取一瓢”。思路是這樣的: 抓取大量(如十萬個)活躍玩家的歷史場次信息,對所有場次的MVP英雄進行統計。十萬個活躍玩家涉及的總Dota場次是千萬級的,統計樣本已經很充足。
有了基本思路,我們再理一個詳盡的流程:
1.抓取數據並保存到本地。(涉及的新手知識:如何抓取網絡數據包、 通過WebClient下載HTML網頁)
2.分析已保存到本地的數據,作出記錄。(涉及的新手知識:簡單的正則表達式、處理JSON)
3.制作直觀統計結果(涉及的新手知識:LINQ和lambda表達式、文件的讀寫)
這么一個簡單的程序,對初學.NET的新手來講,可以帶着興趣鍛煉到如此多的基本功知識點,比看什么枯燥的xxx入門到精通書籍有趣多了! o(∩_∩)o
第一步 用Fiddler抓包獲得用戶統計頁面的URL
通過抓包我們知道:
1.用戶統計頁面的地址形如:
http://i.5211game.com/rating/?u=4629868u后面是用戶的ID
2.需要登錄才能查看統計結果。我們程序獲取頁面時,可以通過設置Cookie來模擬登錄。
第二步 使用WebClient構造請求
Cookie部分設置為Fiddler里所抓取到的Cookie值。如果抓取成功就保存到本地文件,文件名以用戶ID命名。
/// 抓取某個玩家的數據o
/// </summary>
/// <param name="i"> 玩家平台的ID </param>
private void GetFiles( int i)
{
WebClient wc = new WebClient();
wc.Headers.Add( " User-Agent ", " Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.186 Safari/535.1 ");
wc.Headers.Add( " Accept ", " text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 ");
wc.Headers.Add( " Accept-Encoding ", " gzip,deflate,sdch ");
wc.Headers.Add( " Accept-Language ", " zh-CN,zh;q=0.8 ");
wc.Headers.Add( " Accept-Charset ", " GBK,utf-8;q=0.7,*;q=0.3 ");
wc.Headers.Add( " Cookie ", " 設置為你自己的COOKIE ");
wc.DownloadFile( string.Format(urlTemp, beginId + i), (beginId + i).ToString());
}
第三步 分析已抓取文件中的數據
用到了簡單的正則表達式。本例中所處理的對象為JSON,我們采用Newtonsoft.JSON進行處理。將分析結果保存到Dictionary<string,int>數據結構中,同時更新統計的總場次。
/// <summary>
/// </summary>
/// <param name="l"></param>
public void ReadFiles( long l)
{
var sr = File.OpenText(l.ToString());
string content = sr.ReadToEnd();
// 正則表達式提取出HTML文件中的JSON
var m = Regex.Matches(content, " HeroList.*] ", RegexOptions.Compiled);
if (m.Count > 0)
{
// 將JSON變成Record類
var list = JsonConvert.DeserializeObject<List<Record>>(m[ 0].ToString().Replace( " HeroList = ", ""));
foreach ( var item in list)
{
if (!dicMvp.ContainsKey(item.heroname))
{
dicMvp.Add(item.heroname, item.mvp);
}
else
{
dicMvp[item.heroname] = dicMvp[item.heroname] + item.mvp;
}
// 累計場次
BattleCount += item.lost + item.win + item.offline;
}
}
}
第四步 制作直觀的統計結果
軟件的用戶怎么查看程序運營的結果呢?一般無外乎就是文本文件、網頁、圖片。我們先寫個簡單的文本文件吧!。(如果寫個漂亮的HTML5頁面,相信效果會非常好哦)注意在輸出結果前,先把Dictionary<string,int>排序一下,可以使用到簡單的lambda表達式。
/// <summary>
/// </summary>
private void GetResult()
{
var sw = File.CreateText( " result.txt ");
StringBuilder sb = new StringBuilder();
foreach ( var item in dicMvp.OrderByDescending(p => p.Value))
{
sb.AppendFormat( " {0}:{1}\n ", item.Key, item.Value);
}
sw.Write(sb.ToString());
sw.Write( " \n\n總統計場次: " + BattleCount);
sw.Close();
}
運算結果是這樣的:
在已統計的數十萬場比賽中,最容易獲得MVP的英雄前十名依次為:神靈武士、屠夫、嗜血狂魔、賞金獵人、幽鬼、影魔、山嶺巨人、召喚師、敵法師、先知。 當然,如果統計范圍再大一點(把抓取數據的程序跑一整天即可),涉及場次達到千萬級,結果會更加准確。
怎么樣,非常簡單吧?嘿嘿,之前說過了,本文只做拋磚引玉,為那些初學.NET找不到練手項目的人增加一些思路。您可以根據本文很輕松地制作出“最容易打錢的英雄”“殺人數最多的英雄”“最容易推塔的英雄”“最坑爹的英雄”等等等等。。。
關於Dota輔助程序
其實,當您熟知了本文所提及的這些“基礎知識”以后,您會發現11對戰平台的統計數據可以做非常多的事。
關於Dota輔助程序是我一位同事提出的,可以是各種對戰平台(不限於11)的插件形式。可以做的事情有:
1.根據海量統計數據,在某場Dota比賽開始后,根據場上10個英雄,告訴玩家哪個英雄最容易獲得MVP。
2.根據海量統計數據和場上已選的9個英雄,告訴玩家應該選哪個英雄更容易打出好的成績。
3.根據海量統計數據告訴玩家此局應該怎么出裝備、怎么升級能甚至整體策略。
4.根據海量統計數據(尤其是天梯的數據),告訴玩家在CM模式(或其他組隊模式)應該怎么選英雄搭配(還可以結合對方選的英雄實時運算新策略)。
…………
磚已經夠多了,玉就靠你們了。 o(∩_∩)o
有任何問題,歡迎咨詢,劉小排r(新浪微博http://weibo.com/cloudera)知無不言,言無不盡。
文中原代碼下載地址http://files.cnblogs.com/azure/11Stat.rar