相信很多“牛人”都被一些宅男学弟问过这个问题:学长,我作为一个初学程序的菜鸟,要怎么样才能提交自己的编程水平,变成牛人呢?
说实话,这个问题深奥地我有点回答不上来,无外乎只能告诉他“多读”“多写”“搞好数学和算法,练内功”“用好设计模式”“看《编程之美》”等等之类的空话套话。后来剃刀阿遠给出了一个答案让我深受启迪,他说:就一句话——多写给人用的代码。
这句话第一次听上去也许觉得有点装逼,实则不然,我非常认同这个观点。
好吧,宅男学弟又开始问了:学长,什么样的代码才是给人用的代码?毕竟我一个菜鸟我又不是腾讯不能弹窗口邀请别人来用,别人为什么要用一个菜鸟的代码呢?
这个问题相对就更非常具体了,我个人认为,有实用价值同时又让人觉得亲切有趣的程序就可以了。
例如,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
///
/// 玩家平台的ID
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
///
///
///
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
- >(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;
}
}
}