import%20marimo%0A%0A__generated_with%20%3D%20%220.9.20%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20__(mo)%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20%23%23%20%60dicekit%60%0A%0A%20%20%20%20%20%20%20%20The%20goal%20of%20%60dicekit%60%20is%20two-fold.%20%0A%0A%20%20%20%20%20%20%20%20-%20The%20first%20is%20to%20offer%20a%20simple%20library%20to%20interact%20with%20dice.%0A%20%20%20%20%20%20%20%20-%20The%20second%20is%20to%20explore%20how%20Marimo%20may%20give%20us%20a%20domain%20specific%20environment%20to%20work%2Fdevelop%20with%20dice.%20We%20could%20just%20work%20on%20a%20domain%20specific%20languge%2C%20but%20what%20if%20we%20can%20adapt%20the%20environment%20around%20the%20language%20a%20bit%20more%20so%20that%20it%20promotes%20interactivity%20and%20curiosity%20a%20bit%20more%3F%0A%0A%20%20%20%20%20%20%20%20%23%23%20%60Dice%60%20objects%20%0A%0A%20%20%20%20%20%20%20%20The%20main%20object%20that%20you%20will%20interact%20with%20is%20the%20%60Dice%60%20object.%0A%0A%20%20%20%20%20%20%20%20%60%60%60python%0A%20%20%20%20%20%20%20%20from%20dicekit%20import%20Dice%0A%20%20%20%20%20%20%20%20%60%60%60%0A%0A%20%20%20%20%20%20%20%20These%20objects%20give%20you%20a%20flexible%20way%20to%20declare%20dice%2C%20and%20they%20also%20come%20with%20a%20convient%20visualisation%20of%20the%20probability%20distribution%20that%20they%20represent.%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20__(Dice)%3A%0A%20%20%20%20Dice.from_sides(6)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20__(mo)%3A%0A%20%20%20%20mo.md(%22%22%22These%20dice%20can%20be%20stored%20into%20variables%2C%20but%20they%20can%20also%20be%20added%2Fsubtracted%20as%20if%20they%20were%20normal%20Python%20numbers.%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20__(Dice)%3A%0A%20%20%20%20d6%20%3D%20Dice.from_sides(6)%0A%20%20%20%20d8%20%3D%20Dice.from_sides(8)%0A%0A%20%20%20%20d6%20%2B%20d8%0A%20%20%20%20return%20d6%2C%20d8%0A%0A%0A%40app.cell%0Adef%20__(mo)%3A%0A%20%20%20%20mo.md(%22%22%22These%20dice%20have%20a%20bunch%20of%20utilities%20attached%20that%20make%20it%20easy%20to%20get%20the%20distribution%20that%20you%20are%20interested%20in.%20For%20example%2C%20what%20if%20you%20are%20interested%20in%20the%20maximum%20of%20two%20dice%20rolls%3F%20You%20can%20use%20the%20%60.out_of%60%20method%20for%20that.%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20__(Dice%2C%20mo)%3A%0A%20%20%20%20mo.hstack(%5B%0A%20%20%20%20%20%20%20%20Dice.from_sides(20)%2C%20%0A%20%20%20%20%20%20%20%20Dice.from_sides(20).out_of(2%2C%20max)%2C%0A%20%20%20%20%20%20%20%20Dice.from_sides(20).out_of(3%2C%20max)%2C%0A%20%20%20%20%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20__(mo)%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20When%20you%20have%20dice%2C%20you're%20typically%20also%20interested%20in%20their%20probabilities.%20You%20can%20use%20comparison%20operators%20for%20this%2C%20and%20we%20also%20have%20a%20convience%20function%20to%20give%20you%20the%20probability%20that%20you're%20interested%20in.%0A%0A%20%20%20%20%20%20%20%20%60%60%60python%0A%20%20%20%20%20%20%20%20from%20dicekit%20import%20p%2C%20exp%2C%20var%0A%20%20%20%20%20%20%20%20%60%60%60%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20__(Dice%2C%20p)%3A%0A%20%20%20%20d20%20%3D%20Dice.from_sides(20)%0A%0A%20%20%20%20%23%20DnD%20rules%2C%20how%20much%20more%20likely%20are%20you%20to%20win%20when%20you%20are%20at%20advantage%3F%0A%20%20%20%20p(d20.out_of(2%2C%20max)%20%3E%20d20.out_of(2%2C%20min))%0A%20%20%20%20return%20(d20%2C)%0A%0A%0A%40app.cell%0Adef%20__(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22Under%20the%20hood%2C%20a%20comparison%20operator%20merely%20generates%20another%20%60Dice%60.%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20__(d20)%3A%0A%20%20%20%20d20.out_of(2%2C%20max)%20%3E%20d20.out_of(2%2C%20min)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20__(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22There%20are%20also%20some%20other%20convenience%20functions%20available%20such%20as%20%60exp%60%20and%20%60var%60.%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20__(d6%2C%20exp%2C%20var)%3A%0A%20%20%20%20exp(d6)%2C%20var(d6)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20__(mo)%3A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%20%20%20%20%23%23%20Implementation%20%0A%0A%20%20%20%20%20%20%20%20Fun%20fact%3A%20this%20library%20is%20completely%20defined%20and%20maintained%20from%20a%20Marimo%20notebook!%20The%20convenience%20here%20is%20that%20I%20can%20glance%20at%20the%20notebook%20to%20confirm%20if%20it%20is%20working%20and%20it%20also%20reinforces%20a%20good%20documentation%20practice.%20Feel%20free%20to%20explore%20%5Bthe%20repository%5D(https%3A%2F%2Fgithub.com%2Fkoaning%2Fdicekit)%20to%20learn%20out%20it%20is%20set%20up.%20%0A%0A%20%20%20%20%20%20%20%20You%20can%20also%20inspect%20the%20full%20implementation%20below.%20%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20__()%3A%0A%20%20%20%20%23%23%20Export%20%0A%0A%20%20%20%20import%20altair%20as%20alt%20%0A%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20random%20%0A%20%20%20%20from%20collections%20import%20Counter%0A%0A%20%20%20%20class%20Dice%3A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20probs)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.probs%20%3D%20probs%0A%0A%20%20%20%20%20%20%20%20%40classmethod%0A%20%20%20%20%20%20%20%20def%20from_sides(self%2C%20n%3D6)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20Dice(%7Bi%3A%201%2Fn%20for%20i%20in%20range(1%2C%20n%2B1)%7D)%0A%0A%20%20%20%20%20%20%20%20%40classmethod%0A%20%20%20%20%20%20%20%20def%20from_numbers(self%2C%20*args)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20c%20%3D%20Counter(args)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20Dice(%7Bk%3A%20v%2Flen(args)%20for%20k%2C%20v%20in%20args%7D)%0A%0A%20%20%20%20%20%20%20%20def%20roll(self%2C%20n%3D1)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20random.choices(list(self.probs.keys())%2C%20weights%3Dlist(self.probs.values())%2C%20k%3Dn)%0A%0A%20%20%20%20%20%20%20%20def%20operate(self%2C%20other%2C%20operator)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20isinstance(other%2C%20(float%2C%20int))%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20other%20%3D%20Dice(%7Bother%3A%201%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20new_probs%20%3D%20%7B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20s1%2C%20p1%20in%20self.probs.items()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20s2%2C%20p2%20in%20other.probs.items()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20new_key%20%3D%20operator(s1%2C%20s2)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20new_key%20not%20in%20new_probs%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20new_probs%5Bnew_key%5D%20%3D%200%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20new_probs%5Bnew_key%5D%20%2B%3D%20p1%20*%20p2%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20Dice(new_probs)%0A%0A%20%20%20%20%20%20%20%20def%20filter(self%2C%20func)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20new_probs%20%3D%20%7Bk%3A%20v%20for%20k%2C%20v%20in%20self.probs.items()%20if%20func(k)%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20total_prob%20%3D%20sum(new_probs.values())%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20Dice(%7Bk%3A%20v%2Ftotal_prob%20for%20k%2C%20v%20in%20new_probs.items()%7D)%0A%0A%20%20%20%20%20%20%20%20def%20_repr_html_(self)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20mo.as_html(self.prob_chart()).text%0A%0A%20%20%20%20%20%20%20%20def%20prob_chart(self)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20df%20%3D%20pd.DataFrame(%5B%7B%22i%22%3A%20k%2C%20%22p%22%3A%20v%7D%20for%20k%2C%20v%20in%20self.probs.items()%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alt.Chart(df)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.mark_bar()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.encode(x%3D%22i%22%2C%20y%3D%22p%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.properties(title%3D%22Dice%20with%20probabilities%3A%22%2C%20width%3D120%2C%20height%3D120)%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20def%20out_of(self%2C%20n%3D2%2C%20func%3Dmax)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20current%20%3D%20Dice(self.probs)%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20i%20in%20range(n%20-%201)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20current%20%3D%20current.operate(current%2C%20operator%3Dlambda%20a%2C%20b%3A%20func(a%2C%20b))%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20current%0A%0A%20%20%20%20%20%20%20%20def%20__add__(self%2C%20other)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self.operate(other%2C%20lambda%20a%2Cb%3A%20a%20%2B%20b)%0A%0A%20%20%20%20%20%20%20%20def%20__sub__(self%2C%20other)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self.operate(other%2C%20lambda%20a%2Cb%3A%20a%20-%20b)%0A%0A%20%20%20%20%20%20%20%20def%20__mul__(self%2C%20other)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self.operate(other%2C%20lambda%20a%2Cb%3A%20a%20*%20b)%0A%0A%20%20%20%20%20%20%20%20def%20__le__(self%2C%20other)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self.operate(other%2C%20lambda%20a%2Cb%3A%20a%20%3C%3D%20b)%0A%0A%20%20%20%20%20%20%20%20def%20__lt__(self%2C%20other)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self.operate(other%2C%20lambda%20a%2Cb%3A%20a%20%3C%20b)%0A%0A%20%20%20%20%20%20%20%20def%20__ge__(self%2C%20other)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self.operate(other%2C%20lambda%20a%2Cb%3A%20a%20%3E%3D%20b)%0A%0A%20%20%20%20%20%20%20%20def%20__gt__(self%2C%20other)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self.operate(other%2C%20lambda%20a%2Cb%3A%20a%20%3E%20b)%0A%0A%20%20%20%20%20%20%20%20def%20__len__(self)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20len(self.probs)%0A%20%20%20%20return%20Counter%2C%20Dice%2C%20alt%2C%20mo%2C%20pd%2C%20random%0A%0A%0A%40app.cell%0Adef%20__()%3A%0A%20%20%20%20%23%23%20Export%0A%0A%20%20%20%20def%20p(expression)%3A%0A%20%20%20%20%20%20%20%20return%20expression.probs%5BTrue%5D%0A%0A%20%20%20%20def%20exp(dice)%3A%0A%20%20%20%20%20%20%20%20return%20sum(i%20*%20p%20for%20i%2C%20p%20in%20dice.probs.items())%0A%0A%20%20%20%20def%20var(dice)%3A%0A%20%20%20%20%20%20%20%20return%20sum(p%20*%20(i%20-%20exp(dice))**2%20for%20i%2C%20p%20in%20dice.probs.items())%0A%20%20%20%20return%20exp%2C%20p%2C%20var%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
c380080352699bcfdc0448c1886f3f6f57184604ca39e1c86bc18cd0707ac6e6