<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://nethackwiki.com/index.php?action=history&amp;feed=atom&amp;title=User%3AProwler%2FAttribute_distribution</id>
	<title>User:Prowler/Attribute distribution - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://nethackwiki.com/index.php?action=history&amp;feed=atom&amp;title=User%3AProwler%2FAttribute_distribution"/>
	<link rel="alternate" type="text/html" href="https://nethackwiki.com/index.php?title=User:Prowler/Attribute_distribution&amp;action=history"/>
	<updated>2026-06-04T01:31:46Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.32.5</generator>
	<entry>
		<id>https://nethackwiki.com/index.php?title=User:Prowler/Attribute_distribution&amp;diff=204718&amp;oldid=prev</id>
		<title>Prowler: Attribute distribution in 5.0 sampled from the game</title>
		<link rel="alternate" type="text/html" href="https://nethackwiki.com/index.php?title=User:Prowler/Attribute_distribution&amp;diff=204718&amp;oldid=prev"/>
		<updated>2026-05-26T23:25:49Z</updated>

		<summary type="html">&lt;p&gt;Attribute distribution in 5.0 sampled from the game&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;So I figured that with the new reroll option in 5.0 it's reasonably easy to sample the attribute distribution for a role just by starting a new game, sending 100000 'r' inputs and parsing the game output instead of [[Talk:Role#Initial attribute simulation code|running a simulation]]. With this approach, we can also see the effect of strength being increased if the hero is encumbered by the starting inventory, which is hard to sim and supposed to matter for Knights (spoiler: turns out, it doesn't).&lt;br /&gt;
&lt;br /&gt;
Here are the full results. I've also thrown in a few percentiles in addition to the average and the standard deviations.&lt;br /&gt;
NB: The values for Str in this output are raw and not formatted in the usual NetHack fashion, so 19 should be read as 18/01, 20 as 18/02 and so on.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
=== arc hum ===&lt;br /&gt;
Str:	avg=12.51	std=2.12	p10=10	p25=11	p50=12	p75=14	p90=15&lt;br /&gt;
Dex:	avg=9.79	std=1.64	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Con:	avg=12.50	std=2.10	p10=10	p25=11	p50=12	p75=14	p90=15&lt;br /&gt;
Int:	avg=15.33	std=1.87	p10=13	p25=14	p50=15	p75=17	p90=18&lt;br /&gt;
Wis:	avg=15.34	std=1.86	p10=13	p25=14	p50=15	p75=17	p90=18&lt;br /&gt;
Cha:	avg=9.79	std=1.63	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
&lt;br /&gt;
=== arc dwa ===&lt;br /&gt;
Str:	avg=12.76	std=2.10	p10=10	p25=11	p50=13	p75=14	p90=15&lt;br /&gt;
Dex:	avg=9.91	std=1.65	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Con:	avg=12.76	std=2.10	p10=10	p25=11	p50=13	p75=14	p90=15&lt;br /&gt;
Int:	avg=14.93	std=1.31	p10=13	p25=14	p50=15	p75=16	p90=16&lt;br /&gt;
Wis:	avg=14.93	std=1.31	p10=13	p25=14	p50=15	p75=16	p90=16&lt;br /&gt;
Cha:	avg=9.91	std=1.64	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
&lt;br /&gt;
=== arc gno ===&lt;br /&gt;
Str:	avg=12.49	std=2.13	p10=10	p25=11	p50=12	p75=14	p90=15&lt;br /&gt;
Dex:	avg=9.78	std=1.64	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Con:	avg=12.48	std=2.11	p10=10	p25=11	p50=12	p75=14	p90=15&lt;br /&gt;
Int:	avg=15.41	std=2.00	p10=13	p25=14	p50=15	p75=17	p90=18&lt;br /&gt;
Wis:	avg=15.32	std=1.87	p10=13	p25=14	p50=15	p75=17	p90=18&lt;br /&gt;
Cha:	avg=9.78	std=1.64	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
&lt;br /&gt;
=== arc (all races) ===&lt;br /&gt;
Str:	avg=12.59	std=2.12	p10=10	p25=11	p50=12	p75=14	p90=15&lt;br /&gt;
Dex:	avg=9.82	std=1.64	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Con:	avg=12.58	std=2.10	p10=10	p25=11	p50=12	p75=14	p90=15&lt;br /&gt;
Int:	avg=15.23	std=1.77	p10=13	p25=14	p50=15	p75=16	p90=18&lt;br /&gt;
Wis:	avg=15.20	std=1.71	p10=13	p25=14	p50=15	p75=16	p90=18&lt;br /&gt;
Cha:	avg=9.82	std=1.64	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
&lt;br /&gt;
=== bar hum ===&lt;br /&gt;
Str:	avg=18.80	std=1.32	p10=17	p25=18	p50=19	p75=20	p90=20&lt;br /&gt;
Dex:	avg=16.73	std=1.01	p10=15	p25=16	p50=17	p75=18	p90=18&lt;br /&gt;
Con:	avg=17.69	std=0.59	p10=17	p25=17	p50=18	p75=18	p90=18&lt;br /&gt;
Int:	avg=7.61	std=0.87	p10=7	p25=7	p50=7	p75=8	p90=9&lt;br /&gt;
Wis:	avg=7.70	std=0.91	p10=7	p25=7	p50=8	p75=8	p90=9&lt;br /&gt;
Cha:	avg=6.69	std=0.91	p10=6	p25=6	p50=6	p75=7	p90=8&lt;br /&gt;
&lt;br /&gt;
=== bar orc ===&lt;br /&gt;
Str:	avg=18.81	std=1.33	p10=17	p25=18	p50=19	p75=20	p90=20&lt;br /&gt;
Dex:	avg=16.72	std=1.01	p10=15	p25=16	p50=17	p75=18	p90=18&lt;br /&gt;
Con:	avg=17.69	std=0.59	p10=17	p25=17	p50=18	p75=18	p90=18&lt;br /&gt;
Int:	avg=7.60	std=0.86	p10=7	p25=7	p50=7	p75=8	p90=9&lt;br /&gt;
Wis:	avg=7.69	std=0.90	p10=7	p25=7	p50=8	p75=8	p90=9&lt;br /&gt;
Cha:	avg=6.70	std=0.91	p10=6	p25=6	p50=7	p75=7	p90=8&lt;br /&gt;
&lt;br /&gt;
=== bar (all races) ===&lt;br /&gt;
Str:	avg=18.80	std=1.33	p10=17	p25=18	p50=19	p75=20	p90=20&lt;br /&gt;
Dex:	avg=16.72	std=1.01	p10=15	p25=16	p50=17	p75=18	p90=18&lt;br /&gt;
Con:	avg=17.69	std=0.59	p10=17	p25=17	p50=18	p75=18	p90=18&lt;br /&gt;
Int:	avg=7.60	std=0.87	p10=7	p25=7	p50=7	p75=8	p90=9&lt;br /&gt;
Wis:	avg=7.69	std=0.91	p10=7	p25=7	p50=8	p75=8	p90=9&lt;br /&gt;
Cha:	avg=6.69	std=0.91	p10=6	p25=6	p50=6	p75=7	p90=8&lt;br /&gt;
&lt;br /&gt;
=== cav hum ===&lt;br /&gt;
Str:	avg=19.30	std=2.46	p10=16	p25=18	p50=19	p75=21	p90=22&lt;br /&gt;
Dex:	avg=13.20	std=2.17	p10=10	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Con:	avg=16.44	std=1.76	p10=14	p25=15	p50=17	p75=18	p90=18&lt;br /&gt;
Int:	avg=8.90	std=1.40	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Wis:	avg=9.21	std=1.49	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Cha:	avg=8.21	std=1.48	p10=6	p25=7	p50=8	p75=9	p90=10&lt;br /&gt;
&lt;br /&gt;
=== cav dwa ===&lt;br /&gt;
Str:	avg=19.11	std=2.52	p10=16	p25=17	p50=19	p75=21	p90=22&lt;br /&gt;
Dex:	avg=13.09	std=2.22	p10=10	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Con:	avg=16.88	std=2.26	p10=14	p25=15	p50=17	p75=19	p90=20&lt;br /&gt;
Int:	avg=8.87	std=1.40	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Wis:	avg=9.16	std=1.48	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Cha:	avg=8.17	std=1.48	p10=6	p25=7	p50=8	p75=9	p90=10&lt;br /&gt;
&lt;br /&gt;
=== cav gno ===&lt;br /&gt;
Str:	avg=19.30	std=2.46	p10=16	p25=18	p50=19	p75=21	p90=22&lt;br /&gt;
Dex:	avg=13.19	std=2.16	p10=10	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Con:	avg=16.44	std=1.76	p10=14	p25=15	p50=17	p75=18	p90=18&lt;br /&gt;
Int:	avg=8.90	std=1.40	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Wis:	avg=9.21	std=1.49	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Cha:	avg=8.22	std=1.49	p10=6	p25=7	p50=8	p75=9	p90=10&lt;br /&gt;
&lt;br /&gt;
=== cav (all races) ===&lt;br /&gt;
Str:	avg=19.24	std=2.49	p10=16	p25=18	p50=19	p75=21	p90=22&lt;br /&gt;
Dex:	avg=13.16	std=2.18	p10=10	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Con:	avg=16.58	std=1.95	p10=14	p25=15	p50=17	p75=18	p90=18&lt;br /&gt;
Int:	avg=8.89	std=1.40	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Wis:	avg=9.19	std=1.49	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Cha:	avg=8.20	std=1.48	p10=6	p25=7	p50=8	p75=9	p90=10&lt;br /&gt;
&lt;br /&gt;
=== hea hum ===&lt;br /&gt;
Str:	avg=9.16	std=1.42	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Dex:	avg=9.17	std=1.43	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Con:	avg=14.56	std=1.63	p10=13	p25=13	p50=14	p75=16	p90=17&lt;br /&gt;
Int:	avg=9.88	std=1.57	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Wis:	avg=15.78	std=1.40	p10=14	p25=15	p50=16	p75=17	p90=18&lt;br /&gt;
Cha:	avg=16.68	std=0.77	p10=16	p25=16	p50=17	p75=17	p90=18&lt;br /&gt;
&lt;br /&gt;
=== hea gno ===&lt;br /&gt;
Str:	avg=9.18	std=1.42	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Dex:	avg=9.16	std=1.42	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Con:	avg=14.55	std=1.63	p10=13	p25=13	p50=14	p75=16	p90=17&lt;br /&gt;
Int:	avg=9.88	std=1.57	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Wis:	avg=15.78	std=1.40	p10=14	p25=15	p50=16	p75=17	p90=18&lt;br /&gt;
Cha:	avg=16.68	std=0.77	p10=16	p25=16	p50=17	p75=17	p90=18&lt;br /&gt;
&lt;br /&gt;
=== hea (all races) ===&lt;br /&gt;
Str:	avg=9.17	std=1.42	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Dex:	avg=9.17	std=1.42	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Con:	avg=14.56	std=1.63	p10=13	p25=13	p50=14	p75=16	p90=17&lt;br /&gt;
Int:	avg=9.88	std=1.57	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Wis:	avg=15.78	std=1.40	p10=14	p25=15	p50=16	p75=17	p90=18&lt;br /&gt;
Cha:	avg=16.68	std=0.77	p10=16	p25=16	p50=17	p75=17	p90=18&lt;br /&gt;
&lt;br /&gt;
=== kni hum ===&lt;br /&gt;
Str:	avg=14.89	std=1.23	p10=13	p25=14	p50=15	p75=16	p90=16&lt;br /&gt;
Dex:	avg=8.66	std=0.89	p10=8	p25=8	p50=8	p75=9	p90=10&lt;br /&gt;
Con:	avg=11.28	std=1.10	p10=10	p25=10	p50=11	p75=12	p90=13&lt;br /&gt;
Int:	avg=7.97	std=1.01	p10=7	p25=7	p50=8	p75=8	p90=9&lt;br /&gt;
Wis:	avg=14.96	std=0.97	p10=14	p25=14	p50=15	p75=15	p90=16&lt;br /&gt;
Cha:	avg=17.46	std=0.54	p10=17	p25=17	p50=17	p75=18	p90=18&lt;br /&gt;
&lt;br /&gt;
=== mon hum ===&lt;br /&gt;
Str:	avg=17.07	std=2.33	p10=14	p25=15	p50=17	p75=19	p90=20&lt;br /&gt;
Dex:	avg=13.62	std=2.10	p10=11	p25=12	p50=14	p75=15	p90=16&lt;br /&gt;
Con:	avg=11.26	std=1.95	p10=9	p25=10	p50=11	p75=12	p90=14&lt;br /&gt;
Int:	avg=9.85	std=1.66	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Wis:	avg=13.63	std=2.10	p10=11	p25=12	p50=14	p75=15	p90=17&lt;br /&gt;
Cha:	avg=9.85	std=1.66	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
&lt;br /&gt;
=== pri hum ===&lt;br /&gt;
Str:	avg=11.89	std=2.02	p10=9	p25=10	p50=12	p75=13	p90=15&lt;br /&gt;
Dex:	avg=11.90	std=2.02	p10=9	p25=10	p50=12	p75=13	p90=15&lt;br /&gt;
Con:	avg=13.46	std=2.16	p10=11	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Int:	avg=10.26	std=1.74	p10=8	p25=9	p50=10	p75=11	p90=13&lt;br /&gt;
Wis:	avg=17.44	std=1.07	p10=16	p25=17	p50=18	p75=18	p90=18&lt;br /&gt;
Cha:	avg=10.28	std=1.74	p10=8	p25=9	p50=10	p75=11	p90=13&lt;br /&gt;
&lt;br /&gt;
=== pri elf ===&lt;br /&gt;
Str:	avg=11.69	std=1.99	p10=9	p25=10	p50=12	p75=13	p90=14&lt;br /&gt;
Dex:	avg=11.68	std=1.99	p10=9	p25=10	p50=12	p75=13	p90=14&lt;br /&gt;
Con:	avg=13.09	std=1.97	p10=10	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Int:	avg=10.16	std=1.72	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Wis:	avg=18.45	std=1.75	p10=16	p25=17	p50=19	p75=20	p90=20&lt;br /&gt;
Cha:	avg=10.15	std=1.72	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
&lt;br /&gt;
=== pri (all races) ===&lt;br /&gt;
Str:	avg=11.79	std=2.01	p10=9	p25=10	p50=12	p75=13	p90=14&lt;br /&gt;
Dex:	avg=11.79	std=2.01	p10=9	p25=10	p50=12	p75=13	p90=14&lt;br /&gt;
Con:	avg=13.28	std=2.07	p10=11	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Int:	avg=10.21	std=1.73	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Wis:	avg=17.95	std=1.54	p10=16	p25=17	p50=18	p75=19	p90=20&lt;br /&gt;
Cha:	avg=10.22	std=1.73	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
&lt;br /&gt;
=== ran hum ===&lt;br /&gt;
Str:	avg=15.15	std=1.31	p10=14	p25=14	p50=15	p75=16	p90=17&lt;br /&gt;
Dex:	avg=10.45	std=1.17	p10=9	p25=10	p50=10	p75=11	p90=12&lt;br /&gt;
Con:	avg=14.44	std=1.15	p10=13	p25=14	p50=14	p75=15	p90=16&lt;br /&gt;
Int:	avg=13.74	std=0.93	p10=13	p25=13	p50=14	p75=14	p90=15&lt;br /&gt;
Wis:	avg=13.75	std=0.93	p10=13	p25=13	p50=14	p75=14	p90=15&lt;br /&gt;
Cha:	avg=7.75	std=0.93	p10=7	p25=7	p50=8	p75=8	p90=9&lt;br /&gt;
&lt;br /&gt;
=== ran elf ===&lt;br /&gt;
Str:	avg=15.14	std=1.25	p10=14	p25=14	p50=15	p75=16	p90=17&lt;br /&gt;
Dex:	avg=10.46	std=1.17	p10=9	p25=10	p50=10	p75=11	p90=12&lt;br /&gt;
Con:	avg=14.38	std=1.01	p10=13	p25=14	p50=14	p75=15	p90=16&lt;br /&gt;
Int:	avg=13.75	std=0.93	p10=13	p25=13	p50=14	p75=14	p90=15&lt;br /&gt;
Wis:	avg=13.75	std=0.93	p10=13	p25=13	p50=14	p75=14	p90=15&lt;br /&gt;
Cha:	avg=7.75	std=0.93	p10=7	p25=7	p50=8	p75=8	p90=9&lt;br /&gt;
&lt;br /&gt;
=== ran gno ===&lt;br /&gt;
Str:	avg=15.15	std=1.32	p10=14	p25=14	p50=15	p75=16	p90=17&lt;br /&gt;
Dex:	avg=10.45	std=1.17	p10=9	p25=10	p50=10	p75=11	p90=12&lt;br /&gt;
Con:	avg=14.44	std=1.14	p10=13	p25=14	p50=14	p75=15	p90=16&lt;br /&gt;
Int:	avg=13.75	std=0.94	p10=13	p25=13	p50=14	p75=14	p90=15&lt;br /&gt;
Wis:	avg=13.75	std=0.93	p10=13	p25=13	p50=14	p75=14	p90=15&lt;br /&gt;
Cha:	avg=7.75	std=0.94	p10=7	p25=7	p50=8	p75=8	p90=9&lt;br /&gt;
&lt;br /&gt;
=== ran orc ===&lt;br /&gt;
Str:	avg=15.15	std=1.31	p10=14	p25=14	p50=15	p75=16	p90=17&lt;br /&gt;
Dex:	avg=10.45	std=1.17	p10=9	p25=10	p50=10	p75=11	p90=12&lt;br /&gt;
Con:	avg=14.44	std=1.14	p10=13	p25=14	p50=14	p75=15	p90=16&lt;br /&gt;
Int:	avg=13.73	std=0.87	p10=13	p25=13	p50=14	p75=14	p90=15&lt;br /&gt;
Wis:	avg=13.73	std=0.86	p10=13	p25=13	p50=14	p75=14	p90=15&lt;br /&gt;
Cha:	avg=7.75	std=0.94	p10=7	p25=7	p50=8	p75=8	p90=9&lt;br /&gt;
&lt;br /&gt;
=== ran (all races) ===&lt;br /&gt;
Str:	avg=15.15	std=1.30	p10=14	p25=14	p50=15	p75=16	p90=17&lt;br /&gt;
Dex:	avg=10.46	std=1.17	p10=9	p25=10	p50=10	p75=11	p90=12&lt;br /&gt;
Con:	avg=14.43	std=1.11	p10=13	p25=14	p50=14	p75=15	p90=16&lt;br /&gt;
Int:	avg=13.75	std=0.92	p10=13	p25=13	p50=14	p75=14	p90=15&lt;br /&gt;
Wis:	avg=13.74	std=0.91	p10=13	p25=13	p50=14	p75=14	p90=15&lt;br /&gt;
Cha:	avg=7.75	std=0.94	p10=7	p25=7	p50=8	p75=8	p90=9&lt;br /&gt;
&lt;br /&gt;
=== rog hum ===&lt;br /&gt;
Str:	avg=13.78	std=2.26	p10=11	p25=12	p50=14	p75=15	p90=17&lt;br /&gt;
Dex:	avg=17.52	std=0.99	p10=16	p25=18	p50=18	p75=18	p90=18&lt;br /&gt;
Con:	avg=13.72	std=2.17	p10=11	p25=12	p50=14	p75=15	p90=17&lt;br /&gt;
Int:	avg=10.40	std=1.77	p10=8	p25=9	p50=10	p75=11	p90=13&lt;br /&gt;
Wis:	avg=10.41	std=1.77	p10=8	p25=9	p50=10	p75=12	p90=13&lt;br /&gt;
Cha:	avg=9.41	std=1.77	p10=7	p25=8	p50=9	p75=11	p90=12&lt;br /&gt;
&lt;br /&gt;
=== rog orc ===&lt;br /&gt;
Str:	avg=13.78	std=2.26	p10=11	p25=12	p50=14	p75=15	p90=17&lt;br /&gt;
Dex:	avg=17.51	std=1.00	p10=16	p25=17	p50=18	p75=18	p90=18&lt;br /&gt;
Con:	avg=13.73	std=2.18	p10=11	p25=12	p50=14	p75=15	p90=17&lt;br /&gt;
Int:	avg=10.40	std=1.76	p10=8	p25=9	p50=10	p75=11	p90=13&lt;br /&gt;
Wis:	avg=10.41	std=1.76	p10=8	p25=9	p50=10	p75=12	p90=13&lt;br /&gt;
Cha:	avg=9.40	std=1.77	p10=7	p25=8	p50=9	p75=10	p90=12&lt;br /&gt;
&lt;br /&gt;
=== rog (all races) ===&lt;br /&gt;
Str:	avg=13.78	std=2.26	p10=11	p25=12	p50=14	p75=15	p90=17&lt;br /&gt;
Dex:	avg=17.52	std=1.00	p10=16	p25=18	p50=18	p75=18	p90=18&lt;br /&gt;
Con:	avg=13.72	std=2.18	p10=11	p25=12	p50=14	p75=15	p90=17&lt;br /&gt;
Int:	avg=10.40	std=1.76	p10=8	p25=9	p50=10	p75=11	p90=13&lt;br /&gt;
Wis:	avg=10.41	std=1.76	p10=8	p25=9	p50=10	p75=12	p90=13&lt;br /&gt;
Cha:	avg=9.41	std=1.77	p10=7	p25=8	p50=9	p75=10	p90=12&lt;br /&gt;
&lt;br /&gt;
=== sam hum ===&lt;br /&gt;
Str:	avg=15.72	std=1.93	p10=13	p25=14	p50=16	p75=17	p90=18&lt;br /&gt;
Dex:	avg=15.53	std=1.75	p10=13	p25=14	p50=16	p75=17	p90=18&lt;br /&gt;
Con:	avg=17.91	std=0.32	p10=18	p25=18	p50=18	p75=18	p90=18&lt;br /&gt;
Int:	avg=9.93	std=1.38	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Wis:	avg=8.56	std=1.26	p10=7	p25=8	p50=8	p75=9	p90=10&lt;br /&gt;
Cha:	avg=7.56	std=1.27	p10=6	p25=7	p50=7	p75=8	p90=9&lt;br /&gt;
&lt;br /&gt;
=== tou hum ===&lt;br /&gt;
Str:	avg=11.32	std=1.95	p10=9	p25=10	p50=11	p75=13	p90=14&lt;br /&gt;
Dex:	avg=11.32	std=1.93	p10=9	p25=10	p50=11	p75=13	p90=14&lt;br /&gt;
Con:	avg=15.30	std=2.09	p10=12	p25=14	p50=15	p75=17	p90=18&lt;br /&gt;
Int:	avg=12.89	std=1.65	p10=11	p25=12	p50=13	p75=14	p90=15&lt;br /&gt;
Wis:	avg=8.90	std=1.66	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Cha:	avg=15.52	std=1.84	p10=13	p25=14	p50=16	p75=17	p90=18&lt;br /&gt;
&lt;br /&gt;
=== val hum ===&lt;br /&gt;
Str:	avg=18.58	std=2.33	p10=16	p25=17	p50=19	p75=20	p90=22&lt;br /&gt;
Dex:	avg=12.72	std=2.08	p10=10	p25=11	p50=13	p75=14	p90=15&lt;br /&gt;
Con:	avg=17.11	std=1.32	p10=15	p25=16	p50=18	p75=18	p90=18&lt;br /&gt;
Int:	avg=8.76	std=1.35	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Wis:	avg=9.03	std=1.43	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Cha:	avg=9.04	std=1.43	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
&lt;br /&gt;
=== val dwa ===&lt;br /&gt;
Str:	avg=18.26	std=2.36	p10=15	p25=17	p50=18	p75=20	p90=21&lt;br /&gt;
Dex:	avg=12.53	std=2.11	p10=10	p25=11	p50=12	p75=14	p90=15&lt;br /&gt;
Con:	avg=17.82	std=1.94	p10=15	p25=16	p50=18	p75=20	p90=20&lt;br /&gt;
Int:	avg=8.70	std=1.33	p10=7	p25=8	p50=9	p75=9	p90=10&lt;br /&gt;
Wis:	avg=8.97	std=1.42	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Cha:	avg=8.98	std=1.42	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
&lt;br /&gt;
=== val (all races) ===&lt;br /&gt;
Str:	avg=18.42	std=2.35	p10=15	p25=17	p50=18	p75=20	p90=21&lt;br /&gt;
Dex:	avg=12.63	std=2.10	p10=10	p25=11	p50=13	p75=14	p90=15&lt;br /&gt;
Con:	avg=17.47	std=1.70	p10=15	p25=16	p50=18	p75=18	p90=20&lt;br /&gt;
Int:	avg=8.73	std=1.34	p10=7	p25=8	p50=9	p75=9	p90=10&lt;br /&gt;
Wis:	avg=9.00	std=1.43	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
Cha:	avg=9.01	std=1.43	p10=7	p25=8	p50=9	p75=10	p90=11&lt;br /&gt;
&lt;br /&gt;
=== wiz hum ===&lt;br /&gt;
Str:	avg=10.27	std=1.74	p10=8	p25=9	p50=10	p75=11	p90=13&lt;br /&gt;
Dex:	avg=13.47	std=2.16	p10=11	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Con:	avg=13.47	std=2.16	p10=11	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Int:	avg=17.45	std=1.06	p10=16	p25=17	p50=18	p75=18	p90=18&lt;br /&gt;
Wis:	avg=10.28	std=1.73	p10=8	p25=9	p50=10	p75=11	p90=13&lt;br /&gt;
Cha:	avg=10.28	std=1.74	p10=8	p25=9	p50=10	p75=11	p90=13&lt;br /&gt;
&lt;br /&gt;
=== wiz elf ===&lt;br /&gt;
Str:	avg=10.15	std=1.72	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Dex:	avg=13.22	std=2.14	p10=11	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Con:	avg=13.09	std=1.97	p10=10	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Int:	avg=18.46	std=1.74	p10=16	p25=17	p50=19	p75=20	p90=20&lt;br /&gt;
Wis:	avg=10.16	std=1.71	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Cha:	avg=10.15	std=1.71	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
&lt;br /&gt;
=== wiz gno ===&lt;br /&gt;
Str:	avg=10.19	std=1.72	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Dex:	avg=13.30	std=2.15	p10=11	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Con:	avg=13.33	std=2.15	p10=11	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Int:	avg=18.02	std=1.42	p10=16	p25=17	p50=19	p75=19	p90=19&lt;br /&gt;
Wis:	avg=10.19	std=1.73	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
Cha:	avg=10.21	std=1.72	p10=8	p25=9	p50=10	p75=11	p90=12&lt;br /&gt;
&lt;br /&gt;
=== wiz orc ===&lt;br /&gt;
Str:	avg=10.51	std=1.79	p10=8	p25=9	p50=10	p75=12	p90=13&lt;br /&gt;
Dex:	avg=13.90	std=2.16	p10=11	p25=12	p50=14	p75=15	p90=17&lt;br /&gt;
Con:	avg=13.92	std=2.16	p10=11	p25=12	p50=14	p75=15	p90=17&lt;br /&gt;
Int:	avg=15.86	std=0.49	p10=16	p25=16	p50=16	p75=16	p90=16&lt;br /&gt;
Wis:	avg=10.50	std=1.78	p10=8	p25=9	p50=10	p75=12	p90=13&lt;br /&gt;
Cha:	avg=10.51	std=1.77	p10=8	p25=9	p50=10	p75=12	p90=13&lt;br /&gt;
&lt;br /&gt;
=== wiz (all races) ===&lt;br /&gt;
Str:	avg=10.28	std=1.75	p10=8	p25=9	p50=10	p75=11	p90=13&lt;br /&gt;
Dex:	avg=13.47	std=2.17	p10=11	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Con:	avg=13.45	std=2.13	p10=11	p25=12	p50=13	p75=15	p90=16&lt;br /&gt;
Int:	avg=17.45	std=1.60	p10=16	p25=16	p50=18	p75=19	p90=20&lt;br /&gt;
Wis:	avg=10.28	std=1.74	p10=8	p25=9	p50=10	p75=11	p90=13&lt;br /&gt;
Cha:	avg=10.29	std=1.74	p10=8	p25=9	p50=10	p75=11	p90=13&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How to reproduce ==&lt;br /&gt;
&lt;br /&gt;
I'm running it on a clean local NetHack 5.0.0 setup that I run from &amp;lt;code&amp;gt;~/nh/install/games/nethack&amp;lt;/code&amp;gt; (the default path where it's installed on Linux via make install) with the basic .nethackrc:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
OPTIONS=reroll&lt;br /&gt;
OPTIONS=!tutorial&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here's the code for the sampler (sampler.c, to compile: &amp;lt;code&amp;gt;gcc -o sampler sampler.c&amp;lt;/code&amp;gt;).&lt;br /&gt;
This program takes in an amount of samples it needs to generate and a command line to run the game. It expects that the game would immediately start with the reroll screen and will hang if it starts with some other prompt, hence the use of &amp;lt;code&amp;gt;-@&amp;lt;/code&amp;gt; below. It prints the sampled attribute lists, one in a line, in the same form they are presented in game: &amp;lt;code&amp;gt;St:14 Dx:11 Co:12 In:13 Wi:16 Ch:9&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
AI use disclosure: this code was mostly written by an LLM agent.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#define _GNU_SOURCE&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/poll.h&amp;gt;&lt;br /&gt;
#include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
#include &amp;lt;pty.h&amp;gt;&lt;br /&gt;
#include &amp;lt;ctype.h&amp;gt;&lt;br /&gt;
#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;
#include &amp;lt;time.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define BUF_SIZE (1024 * 64)&lt;br /&gt;
&lt;br /&gt;
static void strip_ansi(const char *src, char *dst, size_t dst_cap)&lt;br /&gt;
{&lt;br /&gt;
    size_t j = 0;&lt;br /&gt;
    for (size_t i = 0; src[i] &amp;amp;&amp;amp; j + 1 &amp;lt; dst_cap; ) {&lt;br /&gt;
        if (src[i] == '\x1b' &amp;amp;&amp;amp; src[i + 1] == '[') {&lt;br /&gt;
            i += 2;&lt;br /&gt;
            while (src[i] &amp;amp;&amp;amp; !(isalpha((unsigned char)src[i])))&lt;br /&gt;
                i++;&lt;br /&gt;
            if (src[i]) i++;&lt;br /&gt;
        } else {&lt;br /&gt;
            dst[j++] = src[i++];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    dst[j] = '\0';&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static const char *parse_field_value(const char *p, char *out, size_t *j, size_t cap)&lt;br /&gt;
{&lt;br /&gt;
    while (*p &amp;amp;&amp;amp; isdigit((unsigned char)*p) &amp;amp;&amp;amp; *j + 1 &amp;lt; cap)&lt;br /&gt;
        out[(*j)++] = *p++;&lt;br /&gt;
    if (*p == '/' &amp;amp;&amp;amp; *j + 1 &amp;lt; cap) {&lt;br /&gt;
        out[(*j)++] = *p++;&lt;br /&gt;
        if (*p == '*' &amp;amp;&amp;amp; *(p + 1) == '*' &amp;amp;&amp;amp; *j + 2 &amp;lt; cap) {&lt;br /&gt;
            out[(*j)++] = '*';&lt;br /&gt;
            out[(*j)++] = '*';&lt;br /&gt;
            p += 2;&lt;br /&gt;
        } else {&lt;br /&gt;
            while (*p &amp;amp;&amp;amp; isdigit((unsigned char)*p) &amp;amp;&amp;amp; *j + 1 &amp;lt; cap)&lt;br /&gt;
                out[(*j)++] = *p++;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return p;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static const char *find_stat_line(const char *reroll_pos, char *out, size_t cap,&lt;br /&gt;
                                  size_t *out_len, const char **stat_end)&lt;br /&gt;
{&lt;br /&gt;
    const char *st_pos = strstr(reroll_pos, &amp;quot;St:&amp;quot;);&lt;br /&gt;
    if (!st_pos) {&lt;br /&gt;
        *out_len = 0;&lt;br /&gt;
        *stat_end = NULL;&lt;br /&gt;
        return NULL;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    static const char *labels[] = {&amp;quot;St:&amp;quot;, &amp;quot;Dx:&amp;quot;, &amp;quot;Co:&amp;quot;, &amp;quot;In:&amp;quot;, &amp;quot;Wi:&amp;quot;, &amp;quot;Ch:&amp;quot;};&lt;br /&gt;
    static const size_t lens[] = {3, 3, 3, 3, 3, 3};&lt;br /&gt;
    const char *p = st_pos;&lt;br /&gt;
    size_t j = 0;&lt;br /&gt;
&lt;br /&gt;
    for (int i = 0; i &amp;lt; 6; i++) {&lt;br /&gt;
        if (strncmp(p, labels[i], lens[i]) != 0) {&lt;br /&gt;
            *out_len = 0;&lt;br /&gt;
            *stat_end = NULL;&lt;br /&gt;
            return NULL;&lt;br /&gt;
        }&lt;br /&gt;
        for (size_t k = 0; k &amp;lt; lens[i] &amp;amp;&amp;amp; j + 1 &amp;lt; cap; k++)&lt;br /&gt;
            out[j++] = p[k];&lt;br /&gt;
        p += lens[i];&lt;br /&gt;
        p = parse_field_value(p, out, &amp;amp;j, cap);&lt;br /&gt;
        if (i &amp;lt; 5 &amp;amp;&amp;amp; *p == ' ' &amp;amp;&amp;amp; j + 1 &amp;lt; cap)&lt;br /&gt;
            out[j++] = *p++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    out[j] = '\0';&lt;br /&gt;
    *out_len = j;&lt;br /&gt;
    *stat_end = p;&lt;br /&gt;
    return st_pos;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void send_r(int mfd)&lt;br /&gt;
{&lt;br /&gt;
    for (;;) {&lt;br /&gt;
        ssize_t w = write(mfd, &amp;quot;r&amp;quot;, 1);&lt;br /&gt;
        if (w == 1) return;&lt;br /&gt;
        if (w &amp;lt; 0 &amp;amp;&amp;amp; (errno == EAGAIN || errno == EWOULDBLOCK)) {&lt;br /&gt;
            struct pollfd wpfd = { .fd = mfd, .events = POLLOUT };&lt;br /&gt;
            poll(&amp;amp;wpfd, 1, 100);&lt;br /&gt;
            continue;&lt;br /&gt;
        }&lt;br /&gt;
        if (w &amp;lt; 0 &amp;amp;&amp;amp; errno == EINTR) continue;&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[])&lt;br /&gt;
{&lt;br /&gt;
    int n = 1;&lt;br /&gt;
    int opt;&lt;br /&gt;
&lt;br /&gt;
    while ((opt = getopt(argc, argv, &amp;quot;n:&amp;quot;)) != -1) {&lt;br /&gt;
        switch (opt) {&lt;br /&gt;
        case 'n':&lt;br /&gt;
            n = atoi(optarg);&lt;br /&gt;
            if (n &amp;lt;= 0) {&lt;br /&gt;
                fprintf(stderr, &amp;quot;sampler: -n must be positive\n&amp;quot;);&lt;br /&gt;
                return 1;&lt;br /&gt;
            }&lt;br /&gt;
            break;&lt;br /&gt;
        default:&lt;br /&gt;
            fprintf(stderr, &amp;quot;Usage: sampler -n COUNT -- COMMAND [ARGS...]\n&amp;quot;);&lt;br /&gt;
            return 1;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    int cmd_start = -1;&lt;br /&gt;
    for (int i = 1; i &amp;lt; argc; i++) {&lt;br /&gt;
        if (strcmp(argv[i], &amp;quot;--&amp;quot;) == 0) {&lt;br /&gt;
            cmd_start = i + 1;&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if (cmd_start &amp;lt; 0 || cmd_start &amp;gt;= argc) {&lt;br /&gt;
        fprintf(stderr, &amp;quot;sampler: expected -- followed by command\n&amp;quot;);&lt;br /&gt;
        return 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // make sure we have enough rows for Tou inventory&lt;br /&gt;
    struct winsize ws = { .ws_row = 40, .ws_col = 80 };&lt;br /&gt;
    int mfd;&lt;br /&gt;
    pid_t pid = forkpty(&amp;amp;mfd, NULL, NULL, &amp;amp;ws);&lt;br /&gt;
    if (pid &amp;lt; 0) {&lt;br /&gt;
        perror(&amp;quot;forkpty&amp;quot;);&lt;br /&gt;
        return 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (pid == 0) {&lt;br /&gt;
        setenv(&amp;quot;TERM&amp;quot;, &amp;quot;xterm&amp;quot;, 1);&lt;br /&gt;
        execvp(argv[cmd_start], &amp;amp;argv[cmd_start]);&lt;br /&gt;
        perror(&amp;quot;execvp&amp;quot;);&lt;br /&gt;
        _exit(127);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fcntl(mfd, F_SETFL, fcntl(mfd, F_GETFL) | O_NONBLOCK);&lt;br /&gt;
&lt;br /&gt;
    char *buf = malloc(BUF_SIZE);&lt;br /&gt;
    char *clean = malloc(BUF_SIZE);&lt;br /&gt;
    char stat_out[256];&lt;br /&gt;
    if (!buf || !clean) {&lt;br /&gt;
        perror(&amp;quot;malloc&amp;quot;);&lt;br /&gt;
        return 1;&lt;br /&gt;
    }&lt;br /&gt;
    size_t buflen = 0;&lt;br /&gt;
    int collected = 0;&lt;br /&gt;
    struct pollfd pfd = { .fd = mfd, .events = POLLIN };&lt;br /&gt;
&lt;br /&gt;
    for (;;) {&lt;br /&gt;
        int status;&lt;br /&gt;
        pid_t w = waitpid(pid, &amp;amp;status, WNOHANG);&lt;br /&gt;
        if (w == pid) {&lt;br /&gt;
            fprintf(stderr, &amp;quot;sampler: child exited prematurely\n&amp;quot;);&lt;br /&gt;
            goto done;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        int r = poll(&amp;amp;pfd, 1, 1000);&lt;br /&gt;
        if (r &amp;lt; 0 &amp;amp;&amp;amp; errno != EINTR) {&lt;br /&gt;
            perror(&amp;quot;poll&amp;quot;);&lt;br /&gt;
            goto done;&lt;br /&gt;
        }&lt;br /&gt;
        if (r &amp;lt;= 0) continue;&lt;br /&gt;
&lt;br /&gt;
        for (;;) {&lt;br /&gt;
            ssize_t nr = read(mfd, buf + buflen, BUF_SIZE - buflen - 1);&lt;br /&gt;
            if (nr &amp;lt; 0) {&lt;br /&gt;
                if (errno == EAGAIN || errno == EWOULDBLOCK) break;&lt;br /&gt;
                if (errno == EINTR) continue;&lt;br /&gt;
                if (errno == EIO) { buflen = 0; break; }&lt;br /&gt;
                perror(&amp;quot;read&amp;quot;);&lt;br /&gt;
                goto done;&lt;br /&gt;
            }&lt;br /&gt;
            if (nr == 0) goto done;&lt;br /&gt;
            buflen += (size_t)nr;&lt;br /&gt;
            buf[buflen] = '\0';&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (buflen == 0) continue;&lt;br /&gt;
&lt;br /&gt;
        strip_ansi(buf, clean, BUF_SIZE);&lt;br /&gt;
&lt;br /&gt;
        const char *reroll_pos = strstr(clean, &amp;quot;Reroll this character?&amp;quot;);&lt;br /&gt;
        if (!reroll_pos)&lt;br /&gt;
            continue;&lt;br /&gt;
&lt;br /&gt;
        size_t stat_len;&lt;br /&gt;
        const char *stat_end;&lt;br /&gt;
        if (!find_stat_line(reroll_pos, stat_out, sizeof(stat_out),&lt;br /&gt;
                            &amp;amp;stat_len, &amp;amp;stat_end))&lt;br /&gt;
            continue;&lt;br /&gt;
&lt;br /&gt;
        puts(stat_out);&lt;br /&gt;
        fflush(stdout);&lt;br /&gt;
        collected++;&lt;br /&gt;
&lt;br /&gt;
        if (collected &amp;gt;= n)&lt;br /&gt;
            goto done;&lt;br /&gt;
&lt;br /&gt;
        send_r(mfd);&lt;br /&gt;
        buflen = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
done:&lt;br /&gt;
    kill(pid, SIGHUP);&lt;br /&gt;
    waitpid(pid, NULL, 0);&lt;br /&gt;
    close(mfd);&lt;br /&gt;
    free(buf);&lt;br /&gt;
    free(clean);&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The script that takes in the list of samples and aggregates them into the statistics shown above is called stats.py:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import math&lt;br /&gt;
&lt;br /&gt;
def parse_common(s, prefix):&lt;br /&gt;
    assert s.startswith(prefix+':')&lt;br /&gt;
    return s[len(prefix)+1:]&lt;br /&gt;
&lt;br /&gt;
def parse_strength(s):&lt;br /&gt;
    s = parse_common(s, 'St')&lt;br /&gt;
    try:&lt;br /&gt;
        return int(s)&lt;br /&gt;
    except ValueError:&lt;br /&gt;
        s1, s2 = s.split('/')&lt;br /&gt;
        assert s1 == '18', s1&lt;br /&gt;
        return 18 + int(s2)&lt;br /&gt;
&lt;br /&gt;
def parse_line(line):&lt;br /&gt;
    attrs = line.strip().split()&lt;br /&gt;
    assert len(attrs) == 6&lt;br /&gt;
    return {&lt;br /&gt;
        'Str': parse_strength(attrs[0]),&lt;br /&gt;
        'Dex': int(parse_common(attrs[1], 'Dx')),&lt;br /&gt;
        'Con': int(parse_common(attrs[2], 'Co')),&lt;br /&gt;
        'Int': int(parse_common(attrs[3], 'In')),&lt;br /&gt;
        'Wis': int(parse_common(attrs[4], 'Wi')),&lt;br /&gt;
        'Cha': int(parse_common(attrs[5], 'Ch')),&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
ATTRS = ('Str', 'Dex', 'Con', 'Int', 'Wis', 'Cha')&lt;br /&gt;
PERCENTILES = (10, 25, 50, 75, 90)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    by_attr = {a: [] for a in ATTRS}&lt;br /&gt;
&lt;br /&gt;
    for line in sys.stdin:&lt;br /&gt;
        attrs = parse_line(line)&lt;br /&gt;
        for attr, val in attrs.items():&lt;br /&gt;
            by_attr[attr].append(val)&lt;br /&gt;
&lt;br /&gt;
    for attr in ATTRS:&lt;br /&gt;
        by_attr[attr].sort()&lt;br /&gt;
&lt;br /&gt;
        n = len(by_attr[attr])&lt;br /&gt;
        val_sum = 0&lt;br /&gt;
        val_sq_sum = 0&lt;br /&gt;
        for val in by_attr[attr]:&lt;br /&gt;
            val_sum += val&lt;br /&gt;
            val_sq_sum += val**2&lt;br /&gt;
&lt;br /&gt;
        avg = val_sum / n&lt;br /&gt;
        std = math.sqrt((n*val_sq_sum - val_sum**2) / n**2)&lt;br /&gt;
&lt;br /&gt;
        print(f'{attr}:\tavg={avg:.2f}\tstd={std:.2f}', end='')&lt;br /&gt;
&lt;br /&gt;
        for p in PERCENTILES:&lt;br /&gt;
            print(f'\tp{p}={by_attr[attr][p*n//100]}', end='')&lt;br /&gt;
&lt;br /&gt;
        print()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And finally, the shell script that runs it for all role/race combinations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/sh -e&lt;br /&gt;
&lt;br /&gt;
gcc -o sampler sampler.c&lt;br /&gt;
mkdir -p raw_output&lt;br /&gt;
&lt;br /&gt;
samples=100000&lt;br /&gt;
&lt;br /&gt;
run_role_race()&lt;br /&gt;
{&lt;br /&gt;
    echo &amp;quot;=== $1 $2 ===&amp;quot;&lt;br /&gt;
    ./sampler -n &amp;quot;$samples&amp;quot; -- ~/nh/install/games/nethack -p &amp;quot;$1&amp;quot; -r &amp;quot;$2&amp;quot; -@ | tee &amp;quot;raw_output/${1}_${2}.txt&amp;quot; | ./stats.py&lt;br /&gt;
    echo&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
all_races()&lt;br /&gt;
{&lt;br /&gt;
    echo &amp;quot;=== $1 (all races) ===&amp;quot;&lt;br /&gt;
    cat raw_output/${1}_* | ./stats.py&lt;br /&gt;
    echo&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
run_role_race arc hum&lt;br /&gt;
run_role_race arc dwa&lt;br /&gt;
run_role_race arc gno&lt;br /&gt;
all_races arc&lt;br /&gt;
run_role_race bar hum&lt;br /&gt;
run_role_race bar orc&lt;br /&gt;
all_races bar&lt;br /&gt;
run_role_race cav hum&lt;br /&gt;
run_role_race cav dwa&lt;br /&gt;
run_role_race cav gno&lt;br /&gt;
all_races cav&lt;br /&gt;
run_role_race hea hum&lt;br /&gt;
run_role_race hea gno&lt;br /&gt;
all_races hea&lt;br /&gt;
run_role_race kni hum&lt;br /&gt;
run_role_race mon hum&lt;br /&gt;
run_role_race pri hum&lt;br /&gt;
run_role_race pri elf&lt;br /&gt;
all_races pri&lt;br /&gt;
run_role_race ran hum&lt;br /&gt;
run_role_race ran elf&lt;br /&gt;
run_role_race ran gno&lt;br /&gt;
run_role_race ran orc&lt;br /&gt;
all_races ran&lt;br /&gt;
run_role_race rog hum&lt;br /&gt;
run_role_race rog orc&lt;br /&gt;
all_races rog&lt;br /&gt;
run_role_race sam hum&lt;br /&gt;
run_role_race tou hum&lt;br /&gt;
run_role_race val hum&lt;br /&gt;
run_role_race val dwa&lt;br /&gt;
all_races val&lt;br /&gt;
run_role_race wiz hum&lt;br /&gt;
run_role_race wiz elf&lt;br /&gt;
run_role_race wiz gno&lt;br /&gt;
run_role_race wiz orc&lt;br /&gt;
all_races wiz&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Prowler</name></author>
		
	</entry>
</feed>