2018-04-05 21:23:57 +02:00
|
|
|
from big_ol_pile_of_manim_imports import *
|
|
|
|
from eop.pascal import *
|
|
|
|
|
|
|
|
|
2018-04-06 13:58:49 +02:00
|
|
|
WIDTH = 12
|
|
|
|
HEIGHT = 1
|
|
|
|
GRADE_COLOR_1 = COLOR_HEADS = RED
|
|
|
|
GRADE_COLOR_2 = COLOR_TAILS = BLUE
|
2018-04-06 21:14:35 +02:00
|
|
|
NB_ROWS = 6
|
2018-04-06 13:58:49 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Coin(Circle):
|
|
|
|
CONFIG = {
|
|
|
|
"radius": 0.2,
|
|
|
|
"stroke_width": 3,
|
|
|
|
"stroke_color": WHITE,
|
|
|
|
"fill_opacity": 1,
|
|
|
|
"symbol": "\euro",
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
Circle.__init__(self,**kwargs)
|
|
|
|
self.symbol_mob = TextMobject(self.symbol, stroke_color = self.stroke_color)
|
|
|
|
self.symbol_mob.scale_to_fit_height(0.5*self.get_height()).move_to(self)
|
|
|
|
self.add(self.symbol_mob)
|
|
|
|
|
|
|
|
|
|
|
|
class Heads(Coin):
|
|
|
|
CONFIG = {
|
|
|
|
"fill_color": COLOR_HEADS,
|
|
|
|
"symbol": "H",
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Tails(Coin):
|
|
|
|
CONFIG = {
|
|
|
|
"fill_color": COLOR_TAILS,
|
|
|
|
"symbol": "T",
|
|
|
|
}
|
|
|
|
|
|
|
|
class CoinStack(VGroup):
|
|
|
|
CONFIG = {
|
|
|
|
"spacing": 0.1,
|
|
|
|
"size": 5,
|
|
|
|
"face": Heads,
|
|
|
|
}
|
|
|
|
|
|
|
|
def generate_points(self):
|
|
|
|
for n in range(self.size):
|
|
|
|
coin = self.face()
|
|
|
|
coin.shift(n * self.spacing * RIGHT)
|
|
|
|
self.add(coin)
|
|
|
|
|
|
|
|
class HeadsStack(CoinStack):
|
|
|
|
CONFIG = { "face": Heads }
|
|
|
|
|
|
|
|
class TailsStack(CoinStack):
|
|
|
|
CONFIG = { "face": Tails }
|
|
|
|
|
|
|
|
class TallyStack(VGroup):
|
|
|
|
|
|
|
|
def __init__(self,h,t,**kwargs):
|
|
|
|
self.nb_heads = h
|
|
|
|
self.nb_tails = t
|
|
|
|
VGroup.__init__(self,**kwargs)
|
|
|
|
|
|
|
|
def generate_points(self):
|
|
|
|
stack1 = HeadsStack(size = self.nb_heads)
|
|
|
|
stack2 = TailsStack(size = self.nb_tails)
|
|
|
|
stack2.next_to(stack1, RIGHT, buff = SMALL_BUFF)
|
|
|
|
self.add(stack1, stack2)
|
2018-04-05 21:23:57 +02:00
|
|
|
|
|
|
|
|
|
|
|
class AreaSplittingScene(Scene):
|
|
|
|
|
|
|
|
def create_rect_row(self,n):
|
|
|
|
rects_group = VGroup()
|
|
|
|
for k in range(n+1):
|
|
|
|
proportion = float(choose(n,k)) / 2**n
|
|
|
|
new_rect = Rectangle(
|
|
|
|
width = proportion * WIDTH,
|
|
|
|
height = HEIGHT,
|
|
|
|
fill_color = graded_color(n,k),
|
|
|
|
fill_opacity = 1
|
|
|
|
)
|
|
|
|
new_rect.next_to(rects_group,RIGHT,buff = 0)
|
|
|
|
rects_group.add(new_rect)
|
|
|
|
return rects_group
|
|
|
|
|
|
|
|
def split_rect_row(self,rect_row):
|
|
|
|
|
|
|
|
split_row = VGroup()
|
|
|
|
for rect in rect_row.submobjects:
|
|
|
|
half = rect.copy().stretch_in_place(0.5,0)
|
|
|
|
left_half = half.next_to(rect.get_center(),LEFT,buff = 0)
|
|
|
|
right_half = half.copy().next_to(rect.get_center(),RIGHT,buff = 0)
|
|
|
|
split_row.add(left_half, right_half)
|
|
|
|
return split_row
|
|
|
|
|
2018-04-06 21:14:35 +02:00
|
|
|
|
|
|
|
def rect_center(self,n,i,j):
|
|
|
|
if n < 0:
|
|
|
|
raise Exception("wrong indices " + str(n) + ", " + str(i) + ", " + str(j))
|
|
|
|
if i < 0 or i > n:
|
|
|
|
raise Exception("wrong indices " + str(n) + ", " + str(i) + ", " + str(j))
|
|
|
|
if j > choose(n,i) or j < 0:
|
|
|
|
raise Exception("wrong indices " + str(n) + ", " + str(i) + ", " + str(j))
|
|
|
|
|
|
|
|
rect = self.brick_array[n][i]
|
|
|
|
width = rect.get_width()
|
|
|
|
left_x = rect.get_center()[0] - width/2
|
|
|
|
spacing = width / choose(n,i)
|
|
|
|
x = left_x + (j+0.5) * spacing
|
|
|
|
return np.array([x,rect.get_center()[1], rect.get_center()[2]])
|
|
|
|
|
2018-04-05 21:23:57 +02:00
|
|
|
def construct(self):
|
|
|
|
|
2018-04-06 13:58:49 +02:00
|
|
|
# Draw the bricks
|
|
|
|
|
|
|
|
brick_wall = VGroup()
|
2018-04-05 21:23:57 +02:00
|
|
|
rect_row = self.create_rect_row(0)
|
|
|
|
rect_row.move_to(3.5*UP + 0*HEIGHT*DOWN)
|
|
|
|
self.add(rect_row)
|
2018-04-06 13:58:49 +02:00
|
|
|
brick_wall.add(rect_row)
|
2018-04-06 21:14:35 +02:00
|
|
|
self.brick_array = [[rect_row.submobjects[0]]]
|
2018-04-06 13:58:49 +02:00
|
|
|
|
2018-04-05 21:23:57 +02:00
|
|
|
for n in range(NB_ROWS):
|
|
|
|
# copy and shift
|
|
|
|
new_rect_row = rect_row.copy()
|
|
|
|
self.add(new_rect_row)
|
|
|
|
self.play(new_rect_row.shift,HEIGHT * DOWN)
|
|
|
|
self.wait()
|
|
|
|
|
|
|
|
#split
|
|
|
|
split_row = self.split_rect_row(new_rect_row)
|
|
|
|
self.play(FadeIn(split_row))
|
2018-04-06 13:58:49 +02:00
|
|
|
self.remove(new_rect_row)
|
2018-04-05 21:23:57 +02:00
|
|
|
self.wait()
|
|
|
|
|
|
|
|
# merge
|
|
|
|
rect_row = self.create_rect_row(n+1)
|
|
|
|
rect_row.move_to(3.5*UP + (n+1)*HEIGHT*DOWN)
|
|
|
|
self.play(FadeIn(rect_row))
|
2018-04-06 13:58:49 +02:00
|
|
|
brick_wall.add(rect_row)
|
|
|
|
self.remove(split_row)
|
2018-04-05 21:23:57 +02:00
|
|
|
self.wait()
|
2018-04-06 13:58:49 +02:00
|
|
|
|
|
|
|
# add to brick dict
|
2018-04-06 21:14:35 +02:00
|
|
|
rect_array = []
|
2018-04-06 13:58:49 +02:00
|
|
|
for rect in rect_row.submobjects:
|
2018-04-06 21:14:35 +02:00
|
|
|
rect_array.append(rect)
|
|
|
|
|
|
|
|
self.brick_array.append(rect_array)
|
|
|
|
|
2018-04-06 13:58:49 +02:00
|
|
|
|
2018-04-06 21:14:35 +02:00
|
|
|
self.play(
|
|
|
|
brick_wall.set_fill, {"opacity" : 0.2}
|
|
|
|
)
|
2018-04-06 13:58:49 +02:00
|
|
|
|
|
|
|
|
2018-04-06 21:14:35 +02:00
|
|
|
# Draw the branches
|
|
|
|
|
|
|
|
for (n, rect_row_array) in enumerate(self.brick_array):
|
|
|
|
for (i, rect) in enumerate(rect_row_array):
|
2018-04-06 13:58:49 +02:00
|
|
|
pos = rect.get_center()
|
2018-04-06 21:14:35 +02:00
|
|
|
tally = TallyStack(n - i, i)
|
2018-04-06 13:58:49 +02:00
|
|
|
tally.move_to(pos)
|
|
|
|
|
|
|
|
|
2018-04-06 21:14:35 +02:00
|
|
|
# from the left
|
|
|
|
lines = VGroup()
|
2018-04-06 13:58:49 +02:00
|
|
|
|
2018-04-06 21:14:35 +02:00
|
|
|
if i > 0:
|
|
|
|
for j in range(choose(n-1,i-1)):
|
|
|
|
start_pos = self.rect_center(n-1,i-1,j)
|
|
|
|
end_pos = self.rect_center(n,i,j)
|
|
|
|
lines.add(Line(start_pos,end_pos, stroke_color = GRADE_COLOR_2))
|
|
|
|
self.play(
|
|
|
|
LaggedStart(ShowCreation, lines))
|
|
|
|
|
|
|
|
# from the right
|
|
|
|
lines = VGroup()
|
|
|
|
|
|
|
|
if i < n:
|
|
|
|
for j in range(choose(n-1,i)):
|
|
|
|
start_pos = self.rect_center(n-1,i,j)
|
|
|
|
if i != 0:
|
|
|
|
end_pos = self.rect_center(n,i,choose(n-1,i-1) + j)
|
|
|
|
else:
|
|
|
|
end_pos = self.rect_center(n,i,j)
|
|
|
|
|
|
|
|
lines.add(Line(start_pos,end_pos, stroke_color = GRADE_COLOR_1))
|
|
|
|
self.play(
|
|
|
|
LaggedStart(ShowCreation, lines))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#self.play(FadeIn(tally))
|
2018-04-06 13:58:49 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-04-05 21:23:57 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
2018-04-06 13:58:49 +02:00
|
|
|
self.wait()
|
2018-04-05 21:23:57 +02:00
|
|
|
|
|
|
|
|
|
|
|
|