Simple C# Example - Rating Calculation

Simple C# Example - Rating Calculation

in API Development

Posted by: Snowreap.5174

Snowreap.5174

Here’s a simple example of a C# console-mode program that accesses data from the GW2 API. This code was written for .NET 2.0.

In the default mode of operation, it reads baseline rating information from standard input, gets the current scores from the GW2 API, then calculates new rating, deviation and volatility values for each server and outputs the new information.

The program also has alternative modes (1, 2 and 3) that can be used to predict the likelihood of matchups under the new randomized matchup system. In mode 1, it calculates the likelihood of getting a single server as one of your two opponents. In mode 2, it calculates the likelihood of getting particular pairs of servers as your two opponents. In mode 3, it calculates the likelihood of getting particular world/color combinations (i.e. not just the likelihoods of getting a particular pair of servers, but also the probabilities for each color combination).

None of the alternative modes make use of the API, but I don’t feel like editing out that part of the code just to make this example more API-specific.

The JSON parser implementation is based on earlier code I wrote for a Lua parser, so the “Value” class supports a lot of casting/comparison operators that JSON doesn’t really need.

Note that by posting this code here, I am not giving up ownership of it (I am not making it “public domain”). However, you may still freely look at it, copy it, or modify it. But you may not slap a copyright notice on it then tell me (or others) to stop using it.

-ken

The Purge [PURG] – Ehmry Bay

(edited by Snowreap.5174)

Simple C# Example - Rating Calculation

in API Development

Posted by: Snowreap.5174

Snowreap.5174

Example input (copied directly from the Leaderboard into Notepad):

1 	 Sanctum of Rall	 2221.0640 	 173.5353	 0.7634
2 	 Blackgate	 2157.3918 	 172.9866	 0.7617
3 	 Jade Quarry	 2133.8296 	 172.6257	 0.7609
4 	 Tarnished Coast	 2007.7672 	 172.4862	 0.7597
5 	 Dragonbrand	 1962.8613 	 172.8228	 0.7632
6 	 Fort Aspenwood	 1960.8502 	 172.6732	 0.7589
7 	 Maguuma	 1823.5967 	 174.9570	 0.7723
8 	 Kaineng	 1782.2227 	 175.9198	 0.7935
9 	 Yak's Bend	 1745.0370 	 173.6684	 0.7620
10 	 Sea of Sorrows	 1716.8704 	 180.1183	 0.7736
11 	 Crystal Desert	 1586.2152 	 176.1478	 0.7682
12 	 Ehmry Bay	 1550.0354 	 182.2718	 0.7824
13 	 Stormbluff Isle	 1542.7919 	 177.5990	 0.7761
14 	 Borlis Pass	 1370.9421 	 175.9778	 0.7625
15 	 Anvil Rock	 1287.0150 	 178.1011	 0.7599
16 	 Darkhaven	 1272.9904 	 175.5942	 0.7668
17 	 Sorrow's Furnace	 1219.0934 	 176.3832	 0.7887
18 	 Isle of Janthir	 1215.2333 	 175.5854	 0.7830
19 	 Gate of Madness	 1132.9073 	 174.1129	 0.7631
20 	 Devona's Rest	 1063.6667 	 173.5354	 0.7681
21 	 Northern Shiverpeaks	 1047.4753 	 173.0216	 0.7570
22 	 Henge of Denravi	 1012.8758 	 173.1538	 0.7624
23 	 Ferguson's Crossing	 880.6989 	 173.3165	 0.7702
24 	 Eredon Terrace	 853.4559 	 173.5841	 0.7701

Example output (default mode 0):

1	Sanctum of Rall	2218.4790	172.9671	0.7543	-2.5850	
2	Blackgate	2150.2010	171.9685	0.7525	-7.1908	
3	Jade Quarry	2143.5600	172.1516	0.7518	+9.7304	
4	Dragonbrand	1994.6900	184.8914	0.7568	+31.8287	+1
5	Tarnished Coast	1981.9582	178.2444	0.7521	-25.8090	-1
6	Fort Aspenwood	1926.8598	176.7001	0.7513	-33.9904	
7	Sea of Sorrows	1785.7103	188.2244	0.7687	+68.8399	+3
8	Maguuma	1758.3706	181.6671	0.7665	-65.2261	-1
9	Kaineng	1731.6037	178.2449	0.7853	-50.6190	-1
10	Yak's Bend	1731.4483	174.5728	0.7533	-13.5887	-1
11	Crystal Desert	1652.0692	179.5129	0.7621	+65.8540	
12	Stormbluff Isle	1582.5558	193.7547	0.7708	+39.7639	+1
13	Ehmry Bay	1534.2980	186.1550	0.7745	-15.7374	-1
14	Borlis Pass	1371.7103	177.0362	0.7540	+0.7682	
15	Anvil Rock	1300.5133	180.5061	0.7521	+13.4983	
16	Darkhaven	1236.0851	179.5175	0.7593	-36.9053	
17	Sorrow's Furnace	1199.3135	188.6672	0.7815	-19.7799	
18	Isle of Janthir	1180.9801	184.8205	0.7758	-34.2532	
19	Gate of Madness	1131.7128	174.7810	0.7543	-1.1945	
20	Northern Shiverpeaks	1084.1215	176.6530	0.7495	+36.6462	+1
21	Devona's Rest	1046.5120	177.6124	0.7598	-17.1547	-1
22	Henge of Denravi	1015.3208	178.1281	0.7543	+2.4450	
23	Ferguson's Crossing	932.8182	184.1240	0.7643	+52.1193	
24	Eredon Terrace	869.3953	184.4527	0.7630	+15.9394	

Note that the output can be saved and used as input for a future run, because it is essentially in the same format (the rating change and rank change values are ignored on input). In particular, the Mode 0 output is intended to then be used as input for Mode 1/2/3.

-ken

The Purge [PURG] – Ehmry Bay

(edited by Snowreap.5174)

Simple C# Example - Rating Calculation

in API Development

Posted by: Samuraiken.9581

Samuraiken.9581

Wow, thanks for that ;-) The only thing that I would wish for in an “example” would be more comments (that was some pretty intense math being used, without an explanation of what was going on), but perhaps that’s more because I’m still new to the realm of JSON, etc, and have never used an API before in my life. Well done, though!

Simple C# Example - Rating Calculation

in API Development

Posted by: Ruhrpottpatriot.7293

Ruhrpottpatriot.7293

Also: Holy mother of spaghetti code

Administrator of GW2.NET: GitHub , Forum , NuGet

Simple C# Example - Rating Calculation

in API Development

Posted by: Snowreap.5174

Snowreap.5174

Oh, how standards change over time. For me, spaghetti code has always been “code with a lot of gotos”. In this code, the control flow is very straightforward: it flows from top to bottom, except for loops (which execute top to bottom).

The complaint about a lack of comments is definitely warranted — it wasn’t originally written to be an example; I made it only for my own use, and as such it has all the comments I need. If I get some time I’ll add more comments and upload again.

The one part that is hard to understand is the mode 0 code that does the actual Glicko-2 rating calculation. That part is pretty much a direct implementation of the Glicko-2 algorithm as documented here: http://www.glicko.net/glicko/glicko2.pdf.

The one bit that’s not covered in Glickman’s paper is ArenaNet’s method of calculating a score (represented by “s”), and their choice of a tau value. That information is here: http://www.guildwars2guru.com/news/884-the-math-behind-wvw-ratings/

The Glicko-2 algorithm is impossible to understand just by looking at the code, but it compares fairly directly to the algorithm as described in Glickman’s paper. The algorithm in the paper isn’t particularly easy to understand either so in that respect the code isn’t much worse.

The rest of the modes perform statistical analysis using the Monte Carlo method, where you run a large number of random simulations and count how many of each of the outcomes you get. The code for that is fairly straightforward, but assumes you know how GW2 matchups are done. That information is found here: https://www.guildwars2.com/en/news/big-changes-coming-to-wvw-matchups/.

The JSON code has no comments at all but I’ve provided it only so that the program is complete and will compile — I hadn’t really intended it to be an example of a JSON parser, although if you know the basics of parsing (i.e. the difference between token parsing and lexical analysis), it can certainly serve that purpose. The Value.GetValue() method contains the JSON parser, which consumes tokens from the Tokenizer (aka the Lexical Analyzer) via the Tokenizer.ReadToken() method. If you’ve ever had to write your own parser & lexer before, my implementation will be very clear but if you haven’t this code isn’t intended to teach you how. I suspect most people doing ‘real work’ use tools like bison and flex to auto-generate parsers and lexers, rather than writing them by hand.

-ken

The Purge [PURG] – Ehmry Bay

(edited by Snowreap.5174)

Simple C# Example - Rating Calculation

in API Development

Posted by: Snowreap.5174

Snowreap.5174

Ok, I’ve updated the original post with a newer version of code that has more comments. But the added comments in the main program are not a substitute for understanding the underlying ideas — be sure to check these web pages for the necessary background information:
https://www.guildwars2.com/en/news/big-changes-coming-to-wvw-matchups/
http://www.guildwars2guru.com/news/884-the-math-behind-wvw-ratings/
http://www.glicko.net/glicko/glicko2.pdf

The JSON code is still relatively comment-free, aside from a reference to consult http://www.json.org/. The JSON syntax diagram shown there matches the JSON Tokenizer flow fairly well.

-ken

The Purge [PURG] – Ehmry Bay

Simple C# Example - Rating Calculation

in API Development

Posted by: DarkSpirit.7046

DarkSpirit.7046

Nice job doing it the “man-ly” way – implementing your own parser and all. You can breakup some parts into smaller functions/objects, guilty of that myself, but otherwise it looks fine to me.

(edited by DarkSpirit.7046)