mirror of
https://github.com/3b1b/manim.git
synced 2025-07-31 14:03:59 +08:00
Poker hand scene of eop/bayes
This commit is contained in:
173
eop/bayes.py
173
eop/bayes.py
@ -40,21 +40,23 @@ class BayesOpeningQuote(OpeningQuote):
|
||||
"author" : "Dennis V. Lindley",
|
||||
}
|
||||
|
||||
class IntroducePokerHand(PiCreatureScene):
|
||||
class IntroducePokerHand(PiCreatureScene, SampleSpaceScene):
|
||||
CONFIG = {
|
||||
"community_cards_center" : 1.5*DOWN,
|
||||
"community_card_values" : ["AS", "QH", "10H", "2C", "5H"],
|
||||
"your_hand_values" : ["JS", "KC"],
|
||||
}
|
||||
def construct(self):
|
||||
self.force_skipping()
|
||||
|
||||
self.add_cards()
|
||||
# self.indicate_straight()
|
||||
self.indicate_straight()
|
||||
self.show_flush_potential()
|
||||
self.compute_flush_probability()
|
||||
self.show_flush_sample_space()
|
||||
self.talk_through_sample_space()
|
||||
self.place_high_bet()
|
||||
self.change_belief()
|
||||
self.move_community_cards_out_of_the_way()
|
||||
self.name_bayes_rule()
|
||||
|
||||
def add_cards(self):
|
||||
you, her = self.you, self.her
|
||||
@ -86,6 +88,7 @@ class IntroducePokerHand(PiCreatureScene):
|
||||
self.dither()
|
||||
|
||||
self.community_cards = community_cards
|
||||
self.deck = deck
|
||||
|
||||
def indicate_straight(self):
|
||||
you = self.you
|
||||
@ -234,7 +237,6 @@ class IntroducePokerHand(PiCreatureScene):
|
||||
color = BLUE, buff = SMALL_BUFF
|
||||
)
|
||||
|
||||
self.revert_to_original_skipping_status()
|
||||
self.play(LaggedStart(FadeIn, equation))
|
||||
self.dither(2)
|
||||
self.play(
|
||||
@ -262,23 +264,159 @@ class IntroducePokerHand(PiCreatureScene):
|
||||
you, her = self.you, self.her
|
||||
percentage = self.percentage
|
||||
|
||||
sample_space = SampleSpace()
|
||||
sample_space.add_title()
|
||||
sample_space = self.get_sample_space()
|
||||
sample_space.add_title("Your belief")
|
||||
sample_space.move_to(VGroup(you.hand, her.hand))
|
||||
sample_space.to_edge(UP, buff = MED_SMALL_BUFF)
|
||||
sample_space.shift(RIGHT)
|
||||
p = 1./22
|
||||
top_part, bottom_part = sample_space.divide_horizontally(
|
||||
sample_space.divide_horizontally(
|
||||
p, colors = [SuitSymbol.CONFIG["red"], BLUE_E]
|
||||
)
|
||||
top_label, bottom_label = sample_space.get_side_labels([
|
||||
percentage.get_tex_string(), "95.5\\%"
|
||||
])
|
||||
|
||||
self.revert_to_original_skipping_status()
|
||||
self.play(FadeIn(sample_space))
|
||||
self.play(
|
||||
FadeIn(sample_space),
|
||||
ReplacementTransform(percentage, top_label[1])
|
||||
)
|
||||
self.play(*map(GrowFromCenter, [
|
||||
label[0] for label in top_label, bottom_label
|
||||
]))
|
||||
self.dither(2)
|
||||
self.play(Write(bottom_label[1]))
|
||||
self.dither(2)
|
||||
|
||||
self.sample_space = sample_space
|
||||
|
||||
def talk_through_sample_space(self):
|
||||
her = self.her
|
||||
sample_space = self.sample_space
|
||||
top_part, bottom_part = self.sample_space.horizontal_parts
|
||||
|
||||
flush_hands, non_flush_hands = hand_lists = [
|
||||
[self.get_hand(her, keys) for keys in key_list]
|
||||
for key_list in [
|
||||
[("3H", "8H"), ("4H", "AH"), ("JH", "KH")],
|
||||
[("AC", "6D"), ("3D", "6S"), ("JH", "4C")],
|
||||
]
|
||||
]
|
||||
for hand_list, part in zip(hand_lists, [top_part, bottom_part]):
|
||||
self.play(Indicate(part, scale_factor = 1))
|
||||
for hand in hand_list:
|
||||
hand.save_state()
|
||||
hand.scale(0.01)
|
||||
hand.move_to(part.get_right())
|
||||
self.play(hand.restore)
|
||||
self.dither()
|
||||
self.dither()
|
||||
self.add(top_part, bottom_part)
|
||||
self.play(*map(FadeOut, it.chain(*hand_lists)))
|
||||
|
||||
def place_high_bet(self):
|
||||
pass
|
||||
you, her = self.you, self.her
|
||||
pre_money = VGroup(*[
|
||||
VGroup(*[
|
||||
TexMobject("\\$")
|
||||
for x in range(10)
|
||||
]).arrange_submobjects(RIGHT, buff = SMALL_BUFF)
|
||||
for y in range(4)
|
||||
]).arrange_submobjects(UP, buff = SMALL_BUFF)
|
||||
money = VGroup(*it.chain(*pre_money))
|
||||
money.highlight(GREEN)
|
||||
money.scale(0.8)
|
||||
money.next_to(her.hand, DOWN)
|
||||
for dollar in money:
|
||||
dollar.save_state()
|
||||
dollar.scale(0.01)
|
||||
dollar.move_to(her.get_boundary_point(RIGHT))
|
||||
dollar.set_fill(opacity = 0)
|
||||
|
||||
self.play(LaggedStart(
|
||||
ApplyMethod,
|
||||
money,
|
||||
lambda m : (m.restore,),
|
||||
run_time = 5,
|
||||
))
|
||||
self.play(you.change_mode, "confused")
|
||||
self.dither()
|
||||
|
||||
self.money = money
|
||||
|
||||
def change_belief(self):
|
||||
numbers = VGroup(*[
|
||||
label[1]
|
||||
for label in self.sample_space.horizontal_parts.labels
|
||||
])
|
||||
rect = Rectangle(stroke_width = 0)
|
||||
rect.set_fill(BLACK, 1)
|
||||
rect.stretch_to_fit_width(numbers.get_width())
|
||||
rect.stretch_to_fit_height(self.sample_space.get_height())
|
||||
rect.move_to(numbers, UP)
|
||||
|
||||
self.play(FadeIn(rect))
|
||||
self.change_horizontal_division(
|
||||
0.2,
|
||||
run_time = 3,
|
||||
rate_func = there_and_back,
|
||||
added_anims = [Animation(rect)]
|
||||
)
|
||||
self.play(FadeOut(rect))
|
||||
|
||||
def move_community_cards_out_of_the_way(self):
|
||||
cards = self.community_cards
|
||||
cards.generate_target()
|
||||
cards.target.arrange_submobjects(
|
||||
RIGHT, buff = -cards[0].get_width() + MED_SMALL_BUFF,
|
||||
)
|
||||
cards.target.move_to(self.deck)
|
||||
cards.target.to_edge(LEFT)
|
||||
|
||||
self.sample_space.add(self.sample_space.horizontal_parts.labels)
|
||||
|
||||
self.play(
|
||||
self.deck.scale, 0.7,
|
||||
self.deck.next_to, cards.target, UP,
|
||||
self.deck.to_edge, LEFT,
|
||||
self.sample_space.shift, 3*DOWN,
|
||||
MoveToTarget(cards)
|
||||
)
|
||||
|
||||
def name_bayes_rule(self):
|
||||
title = TextMobject("Bayes' rule")
|
||||
title.highlight(BLUE)
|
||||
title.to_edge(UP)
|
||||
subtitle = TextMobject("Update ", "prior ", "beliefs")
|
||||
subtitle.scale(0.8)
|
||||
subtitle.next_to(title, DOWN)
|
||||
prior_word = subtitle.get_part_by_tex("prior")
|
||||
numbers = VGroup(*[
|
||||
label[1] for label in self.sample_space.horizontal_parts.labels
|
||||
])
|
||||
rect = SurroundingRectangle(numbers, color = GREEN)
|
||||
arrow = Arrow(prior_word.get_bottom(), rect.get_top())
|
||||
arrow.highlight(GREEN)
|
||||
|
||||
words = TextMobject(
|
||||
"Maybe she really \\\\ does have a flush $\\dots$",
|
||||
alignment = ""
|
||||
)
|
||||
words.scale(0.7)
|
||||
words.next_to(self.money, DOWN, aligned_edge = LEFT)
|
||||
|
||||
self.play(
|
||||
Write(title, run_time = 2),
|
||||
self.you.change_mode, "pondering"
|
||||
)
|
||||
self.dither()
|
||||
self.play(FadeIn(subtitle))
|
||||
self.play(prior_word.highlight, GREEN)
|
||||
self.play(
|
||||
ShowCreation(rect),
|
||||
ShowCreation(arrow)
|
||||
)
|
||||
self.dither(3)
|
||||
self.play(Write(words))
|
||||
self.dither(3)
|
||||
|
||||
|
||||
######
|
||||
@ -337,9 +475,14 @@ class HowDoesPokerWork(TeacherStudentsScene):
|
||||
self.change_student_modes(*["confused"]*3)
|
||||
self.dither(2)
|
||||
|
||||
class ShowCountingArgument(IntroducePokerHand):
|
||||
class YourGutKnowsBayesRule(TeacherStudentsScene):
|
||||
def construct(self):
|
||||
pass
|
||||
self.teacher_says(
|
||||
"Your gut knows \\\\ Bayes' rule.",
|
||||
run_time = 1
|
||||
)
|
||||
self.change_student_modes("confused", "gracious", "guilty")
|
||||
self.dither(3)
|
||||
|
||||
|
||||
|
||||
|
@ -63,7 +63,6 @@ class TexMobject(SVGMobject):
|
||||
#specialized path_string mobject
|
||||
return TexSymbol(path_string)
|
||||
|
||||
|
||||
def generate_points(self):
|
||||
SVGMobject.generate_points(self)
|
||||
if len(self.args) > 1:
|
||||
|
@ -1,12 +1,52 @@
|
||||
from helpers import *
|
||||
|
||||
from scene import Scene
|
||||
|
||||
from animation.animation import Animation
|
||||
from animation.transform import Transform
|
||||
|
||||
from mobject import Mobject
|
||||
from mobject.vectorized_mobject import VGroup, VMobject, VectorizedPoint
|
||||
from mobject.svg_mobject import SVGMobject
|
||||
from mobject.tex_mobject import TextMobject, TexMobject
|
||||
from mobject.tex_mobject import TextMobject, TexMobject, Brace
|
||||
|
||||
from topics.geometry import Circle, Line, Rectangle, Square, Arc, Polygon
|
||||
|
||||
EPSILON = 0.0001
|
||||
|
||||
class SampleSpaceScene(Scene):
|
||||
def get_sample_space(self, **config):
|
||||
self.sample_space = SampleSpace(**config)
|
||||
return self.sample_space
|
||||
|
||||
def add_sample_space(self, **config):
|
||||
self.add(self.get_sample_space(**config))
|
||||
|
||||
def change_horizontal_division(self, p_list, **kwargs):
|
||||
assert(hasattr(self.sample_space, "horizontal_parts"))
|
||||
added_anims = kwargs.pop("added_anims", [])
|
||||
new_division_kwargs = kwargs.pop("new_division_kwargs", {})
|
||||
added_label_kwargs = kwargs.pop("label_kwargs", {})
|
||||
|
||||
curr_parts = self.sample_space.horizontal_parts
|
||||
new_division_kwargs["colors"] = [
|
||||
part.get_color() for part in curr_parts
|
||||
]
|
||||
new_parts = self.sample_space.get_horizontal_division(
|
||||
p_list, **new_division_kwargs
|
||||
)
|
||||
anims = [Transform(curr_parts, new_parts)]
|
||||
if hasattr(curr_parts, "labels"):
|
||||
label_kwargs = curr_parts.label_kwargs
|
||||
label_kwargs.update(added_label_kwargs)
|
||||
new_labels = self.sample_space.get_subdivision_labels(
|
||||
new_parts, **label_kwargs
|
||||
)
|
||||
anims.append(Transform(curr_parts.labels, new_labels))
|
||||
anims += added_anims
|
||||
|
||||
self.play(*anims, **kwargs)
|
||||
|
||||
|
||||
class SampleSpace(VGroup):
|
||||
CONFIG = {
|
||||
@ -16,7 +56,8 @@ class SampleSpace(VGroup):
|
||||
"fill_color" : DARK_GREY,
|
||||
"fill_opacity" : 0.8,
|
||||
"stroke_width" : 0,
|
||||
}
|
||||
},
|
||||
"default_label_scale_val" : 0.7,
|
||||
}
|
||||
def __init__(self, **kwargs):
|
||||
VGroup.__init__(self, **kwargs)
|
||||
@ -31,31 +72,84 @@ class SampleSpace(VGroup):
|
||||
title_mob.next_to(self.full_space, UP, buff = buff)
|
||||
self.title = title_mob
|
||||
self.add(title_mob)
|
||||
|
||||
def add_label(self, label):
|
||||
self.label = label
|
||||
|
||||
def divide_along_dimension(self, p, dim, colors):
|
||||
def get_division_along_dimension(self, p_list, dim, colors, vect):
|
||||
p_list = list(tuplify(p_list))
|
||||
if abs(1.0 - sum(p_list)) > EPSILON:
|
||||
p_list.append(1.0 - sum(p_list))
|
||||
colors = color_gradient(colors, len(p_list))
|
||||
perp_dim = 1-dim
|
||||
if dim == 0:
|
||||
vects = [UP, DOWN]
|
||||
else:
|
||||
vects = [LEFT, RIGHT]
|
||||
|
||||
last_point = self.full_space.get_edge_center(-vect)
|
||||
parts = VGroup()
|
||||
for factor, vect, color in zip([p, 1-p], vects, colors):
|
||||
part = self.full_space.copy()
|
||||
for factor, color in zip(p_list, colors):
|
||||
part = SampleSpace()
|
||||
part.set_fill(color, 1)
|
||||
part.replace(self.full_space, stretch = True)
|
||||
part.stretch(factor, perp_dim)
|
||||
part.move_to(self.full_space, vect)
|
||||
part.move_to(last_point, -vect)
|
||||
last_point = part.get_edge_center(vect)
|
||||
parts.add(part)
|
||||
return parts
|
||||
|
||||
def divide_horizontally(self, p, colors = [GREEN_E, RED_E]):
|
||||
result = self.divide_along_dimension(p, 0, colors)
|
||||
self.top_part, self.bottom_part = result
|
||||
return result
|
||||
def get_horizontal_division(
|
||||
self, p_list,
|
||||
colors = [GREEN_E, BLUE],
|
||||
vect = DOWN
|
||||
):
|
||||
return self.get_division_along_dimension(p_list, 0, colors, vect)
|
||||
|
||||
def get_vertical_division(
|
||||
self, p_list,
|
||||
colors = [MAROON_B, YELLOW],
|
||||
vect = RIGHT
|
||||
):
|
||||
return self.get_division_along_dimension(p_list, 1, colors, vect)
|
||||
|
||||
def divide_horizontally(self, *args, **kwargs):
|
||||
self.horizontal_parts = self.get_horizontal_division(*args, **kwargs)
|
||||
self.add(self.horizontal_parts)
|
||||
|
||||
def divide_vertically(self, *args, **kwargs):
|
||||
self.vertical_parts = self.get_vertical_division(*args, **kwargs)
|
||||
self.add(self.vertical_parts)
|
||||
|
||||
def get_subdivision_labels(self, parts, labels, direction, buff = SMALL_BUFF):
|
||||
label_brace_groups = VGroup()
|
||||
for label, part in zip(labels, parts):
|
||||
brace = Brace(part, direction, min_num_quads = 1, buff = buff)
|
||||
label_mob = TexMobject(label)
|
||||
label_mob.scale(self.default_label_scale_val)
|
||||
label_mob.next_to(brace, direction, buff)
|
||||
full_label = VGroup(brace, label_mob)
|
||||
part.add_label(full_label)
|
||||
label_brace_groups.add(full_label)
|
||||
parts.labels = label_brace_groups
|
||||
parts.label_kwargs = {
|
||||
"labels" : labels,
|
||||
"direction" : direction,
|
||||
"buff" : buff,
|
||||
}
|
||||
return label_brace_groups
|
||||
|
||||
def get_side_labels(self, labels, direction = LEFT, **kwargs):
|
||||
assert(hasattr(self, "horizontal_parts"))
|
||||
parts = self.horizontal_parts
|
||||
return self.get_subdivision_labels(parts, labels, direction, **kwargs)
|
||||
|
||||
def get_top_labels(self, labels, **kwargs):
|
||||
assert(hasattr(self, "vertical_parts"))
|
||||
parts = self.vertical_parts
|
||||
return self.get_subdivision_labels(parts, labels, UP, **kwargs)
|
||||
|
||||
def get_bototm_labels(self, labels, **kwargs):
|
||||
assert(hasattr(self, "vertical_parts"))
|
||||
parts = self.vertical_parts
|
||||
return self.get_subdivision_labels(parts, labels, DOWN, **kwargs)
|
||||
|
||||
def divide_vertically(self, p, colors = [MAROON_B, YELLOW]):
|
||||
result = self.divide_along_dimension(p, 1, colors)
|
||||
self.left_part, self.right_part = result
|
||||
return result
|
||||
|
||||
### Cards ###
|
||||
|
||||
@ -225,7 +319,8 @@ class PlayingCard(VGroup):
|
||||
)
|
||||
sub_rect.move_to(self)
|
||||
|
||||
pi_color = average_color(symbol.get_color(), GREY)
|
||||
# pi_color = average_color(symbol.get_color(), GREY)
|
||||
pi_color = symbol.get_color()
|
||||
pi_mode = {
|
||||
"J" : "plain",
|
||||
"Q" : "thinking",
|
||||
@ -305,3 +400,22 @@ class SuitSymbol(SVGMobject):
|
||||
self.set_stroke(width = 0)
|
||||
self.set_fill(color, 1)
|
||||
self.scale_to_fit_height(self.height)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user