Skip to content

Instantly share code, notes, and snippets.

@Wikunia
Created Jun 8, 2021
Embed
What would you like to do?
using Animations
using Colors
using Javis
struct SudokuAnim
size :: Int
xoffset :: Int
yoffset :: Int
vlines :: Vector{Javis.Object}
hlines :: Vector{Javis.Object}
cells :: Array{Javis.Object, 2}
end
function ground(video, args...)
sethue("white")
background("black")
translate(-video.width ÷ 2, -video.height ÷ 2)
fontface("Georgia")
end
function show_title(video, args...)
fontsize(100)
translate(video.width ÷ 2, video.height ÷ 2)
text("Solving Sudokus Like A Human"; valign=valign=:middle, halign=:center)
end
function show_subtitle(video, args...; s="Sudoku", fsize=50)
isempty(s) && return
fontsize(fsize)
translate(video.width ÷ 2, video.height ÷ 2)
translate(-900, 0)
textwrap(s, 550, O)
end
function show_berge(video, args...)
translate(video.width ÷ 2, video.height ÷ 2)
translate(-950, -200)
fontsize(35)
text("Finding all matchings is too slow")
translate(0, 100)
fontsize(50)
text("Berge's Lemma:")
translate(0, 60)
fontsize(32)
text("An edge belongs to some but not")
translate(0, 40)
text("all maximum matchings if and only if,")
translate(0, 40)
text("given a maximum matching")
translate(0, 40)
text("it belongs to either")
translate(0, 40)
text("- an even alternating path")
translate(0, 40)
text(" starting at a free vertex")
translate(0, 40)
text("- an even alternating cycle")
translate(0, 100)
fontsize(50)
text("alternating between:")
translate(0, 50)
text("blue and white")
end
function myhline(start, width, linewidth)
setline(linewidth)
translate(start, 0)
line(O, Point(width, 0), :stroke)
end
function myvline(start, height, linewidth)
setline(linewidth)
translate(0, start)
line(O, Point(0, height), :stroke)
end
function arrow_line(sudoku_size, from_sudoku, from_row, from_col, to_col; t=1, linewidth=2)
p1 = pos(from_sudoku.cells[from_row, from_col])+Point(0, sudoku_size/18)
# Todo: Use pos with to_sudoku which currrently fails somehow
p2 = p1+Point(-from_col*sudoku_size/9, 0)+Point(to_col*sudoku_size/9, 4*sudoku_size/9-sudoku_size/18)
circle(p1, 5, :fill)
circle(p2, 5, :fill)
setline(linewidth)
line(p1, p1+(p2-p1)*t, :stroke)
end
function get_line_objects(frames, size_sudoku; anim_draw_len=30, xoffset=100, yoffset=100)
hlines = [Object(frames, (args...; start=0, width=0, linewidth=2)->myhline(start, width, linewidth), Point(xoffset, yoffset+i*(size_sudoku / 9))) for i in 1:8]
act!(hlines, Action(1:anim_draw_len-1, change(:width, 0 => size_sudoku)))
act!(hlines[[3,6]], Action(1:1, change(:linewidth, 6)))
vlines = [Object(frames, (args...; start=0, height=0, linewidth=2)->myvline(start, height, linewidth), Point(xoffset+i*(size_sudoku / 9), yoffset)) for i in 1:8]
act!(vlines, Action(1:anim_draw_len-1, change(:height, 0 => size_sudoku)))
act!(vlines[[3,6]], Action(1:1, change(:linewidth, 6)))
return (hlines = hlines, vlines = vlines)
end
function sudoku_cell(numbers, fixed, color; fsize_fixed=50, fsize_all=28, size=0, extra=-1)
isempty(numbers) && return O
@layer begin
if fixed
if numbers[1] == extra
sethue("#3C86F1")
else
sethue(color)
end
fontsize(fsize_fixed)
text(string(numbers[1]); valign=valign=:middle, halign=:center)
else
fontsize(fsize_all)
# sethue("red")
# circle(O, 5, :fill)
w, h = textextents("1")[[3,4]]
translate(-(size ÷ 2), -(size ÷ 2))
# sethue("orange")
# circle(O, 5, :fill)
translate(w / 2 + fsize_all/2, h / 2 + 8)
for i=1:3
for j=1:3
n = (i-1)*3+j
if n == extra
setopacity(1.0)
sethue("#3C86F1")
else
if n in numbers
setopacity(1.0)
sethue("#5FFA8E") # green
else
setopacity(0.8)
sethue("#F33D1D") # red
end
end
text(string(n); valign=:middle, halign=:center)
translate(fsize_all-13, 0)
end
translate(-3*(fsize_all-13), fsize_all-6)
end
end
end
return O
end
function cell_highlight(l, color, width, height)
setline(8)
sethue(color)
# penultimate is corner radius
if l == 1
box(O, width, height, 10, :stroke)
else
box(O, width, height, 10, :path)
p = pathtopoly()[1]
push!(p, p[1])
points = polyportion(polysample(p, 1000), l)
poly(points, :stroke)
end
end
function create_sudoku_objects(frames, size_sudoku; xoffset=100, yoffset=100)
so = Array{Object}(undef, (9,9))
changed = Array{Object}(undef, (9,9))
for i in 1:9, j in 1:9
so[i,j] = Object(frames, (args...; numbers="", fixed=false, color="white", fsize_fixed=50, fsize_all=28, size=size_sudoku/9, extra=-1)->sudoku_cell(numbers, fixed, color; fsize_fixed, fsize_all, size, extra), Point(xoffset+(j-1)*(size_sudoku/9)+(size_sudoku/18), yoffset+(i-1)*(size_sudoku/9)+(size_sudoku/18)))
changed[i,j] = Object(frames, (args...; l=0.0, color="yellow", width=size_sudoku/9, height=size_sudoku/9)->cell_highlight(l, color, width, height), Point(xoffset+(j-1)*(size_sudoku/9)+(size_sudoku/18), yoffset+(i-1)*(size_sudoku/9)+(size_sudoku/18)))
end
return so, changed
end
function set_sudoku_grid(so, grid; framestart=1, anim_draw_len=10)
for i in 1:9, j=1:9
if grid[i,j] != 0
act!(so[i,j], Action(framestart:framestart, change(:numbers, [grid[i,j]])))
act!(so[i,j], Action(framestart:framestart, change(:fixed, true)))
act!(so[i,j], Action(framestart:framestart+anim_draw_len-1, appear(:fade)))
end
end
end
function compute_possible(grid, i, j)
if grid[i,j] != 0
return Set(grid[i,j]), Set{Int}(), Set{Int}(), Set{Int}()
end
possible = Set(1:9)
row = Set(grid[i,k] != 0 ? grid[i,k] : 0 for k in 1:9)
col = Set(grid[k,j] != 0 ? grid[k,j] : 0 for k in 1:9)
rb = (i-1) ÷ 3
cb = (j-1) ÷ 3
block = Set(grid[rb*3+k1,cb*3+k2] != 0 ? grid[rb*3+k1,cb*3+k2] : 0 for k1 in 1:3, k2 in 1:3)
setdiff!(possible, row, col, block)
return possible, row, col, block
end
function set_sudoku_immediate_impossible(so, grid, grid_possible; framestart=1, anim_draw_len=10, is=1:9, js=1:9, parts=[:row,:col,:block], fixing=false, just_fixing=true)
changed = zeros(Bool, (9,9))
possible_arr = Array{Array{Int}}(undef, (9,9))
b_changed = true
for i in is, j=js
possible_arr[i,j] = Int[]
end
while b_changed
b_changed = false
for i in is, j=js
if grid[i,j] == 0
possible = Set(1:9)
_, row, col, block = compute_possible(grid, i, j)
non_possible_parts = (row = row, col = col, block = block)
for p in parts
setdiff!(possible, non_possible_parts[p])
end
if possible != grid_possible[i,j]
changed[i,j] = true
end
grid_possible[i,j] = possible
possible_arr[i,j] = collect(possible)
if fixing && length(possible) == 1
changed[i,j] = true
if !just_fixing
# fix new ones
grid[i,j] = collect(possible)[1]
b_changed = true
break
end
end
end
end
end
for i in is, j in js
if !isempty(possible_arr[i,j])
possible = possible_arr[i,j]
act!(so[i,j], Action(framestart:framestart, change(:numbers, collect(possible))))
if fixing && length(possible) == 1
act!(so[i,j], Action(framestart:framestart, change(:fixed, true)))
act!(so[i,j], Action(framestart:framestart, change(:color, "#5FFA8E")))
grid[i,j] = collect(possible)[1]
else
act!(so[i,j], Action(framestart:framestart, change(:fixed, false)))
end
act!(so[i,j], Action(framestart:framestart+anim_draw_len-1, appear(:fade)))
end
end
return changed
end
function set_subtitle!(subtitle, start, s; len=30, fsize=50)
act!(subtitle, Action(start:start, change(:fsize, fsize)))
act!(subtitle, Action(start:start, change(:s, s)))
act!(subtitle, Action(start:start+15, appear(:fade)))
act!(subtitle, Action(start+len-15:start+len, disappear(:fade)))
end
function show_changed(cso, changed, start; len=50, anim_length=30)
for c in findall(changed)
act!(cso[c], Action(start:start+anim_length, change(:l, 0.0 => 1.0)))
act!(cso[c], Action(start+len-anim_length:start+len, change(:l, 1.0 => 0.0)))
end
end
function focus_on_row(grid_start, cframe, row, sudoku_anim, subtitle, subtitle_size; shift=:up, mark_row=true, do_anim=true)
size_sudoku = sudoku_anim.size
xoffset = sudoku_anim.xoffset
yoffset = sudoku_anim.yoffset
so = sudoku_anim.cells
if mark_row
set_subtitle!(subtitle, cframe, "Focusing on one row"; len=100, fsize=subtitle_size)
row_highlight = Object(grid_start+cframe:grid_start+cframe+100, (args...; l=0.0, color="yellow", width=size_sudoku, height=size_sudoku/9)->cell_highlight(l, color, width, height), Point(xoffset+4.5*(size_sudoku/9), yoffset+(row-1)*(size_sudoku/9)+(size_sudoku/18)))
act!(row_highlight, Action(1:20, change(:l, 0.0 => 1.0)))
act!(row_highlight, Action(81:100, change(:l, 1.0 => 0.0)))
cframe += 100
end
anim_len = do_anim ? 20 : 0
for i = 1:8
(i == row || i == row-1) && continue
act!(sudoku_anim.hlines[i], Action(cframe:cframe+anim_len, change(:width, size_sudoku => 0)))
end
act!(sudoku_anim.vlines, Action(cframe:cframe+anim_len, change(:height, size_sudoku => size_sudoku/9)))
act!(sudoku_anim.vlines, Action(cframe:cframe+anim_len, change(:start, 0 => (row-1)*size_sudoku/9)))
for i in 1:9
i == row && continue
act!(so[i,1:9], Action(cframe:cframe+anim_len, disappear(:fade)))
end
anim_len = do_anim ? 30 : 0
if shift == :up
do_anim && (cframe += 100)
# shifting up
for i = 1:9
act!(sudoku_anim.cells[i,1:9], Action(cframe:cframe+anim_len, anim_translate(-100, -(size_sudoku/9)*row)))
end
act!(sudoku_anim.vlines, Action(cframe:cframe+anim_len, anim_translate(-100, -(size_sudoku/9)*row)))
act!(sudoku_anim.hlines, Action(cframe:cframe+anim_len, anim_translate(-100, -(size_sudoku/9)*row)))
elseif shift == :down
do_anim && (cframe += 100)
# shifting down
for i = 1:9
act!(sudoku_anim.cells[i,1:9], Action(cframe:cframe+anim_len, anim_translate(-100, (size_sudoku/9)*(9-row))))
end
act!(sudoku_anim.vlines, Action(cframe:cframe+anim_len, anim_translate(-100, (size_sudoku/9)*(9-row))))
act!(sudoku_anim.hlines, Action(cframe:cframe+anim_len, anim_translate(-100, (size_sudoku/9)*(9-row))))
end
do_anim && (cframe += 100)
act!(sudoku_anim.hlines[row], Action(cframe:cframe+anim_len, anim_translate(0, (size_sudoku/9))))
act!(sudoku_anim.hlines[[row, row-1]], Action(cframe:cframe+anim_len, change(:start, 0 => -4.5*(size_sudoku/9))))
act!(sudoku_anim.hlines[[row, row-1]], Action(cframe:cframe+anim_len, change(:width, size_sudoku => 2*size_sudoku)))
for j in 1:8
act!(sudoku_anim.vlines[j], Action(cframe:cframe+anim_len, anim_translate((j-4.5)*(size_sudoku/9), 0)))
act!(sudoku_anim.vlines[j], Action(cframe:cframe+anim_len, change(:height, size_sudoku/9 => 2*size_sudoku/9)))
end
for j in 1:9
act!(sudoku_anim.cells[row,j], Action(cframe:cframe+anim_len, anim_translate((j-5)*(size_sudoku/9), (size_sudoku/18))))
act!(sudoku_anim.cells[row,j], Action(cframe:cframe+anim_len, change(:size, size_sudoku/9 => 2*size_sudoku/9)))
act!(sudoku_anim.cells[row,j], Action(cframe:cframe+anim_len, change(:fsize_fixed, 50 => 80)))
act!(sudoku_anim.cells[row,j], Action(cframe:cframe+anim_len, change(:fsize_all, 28 => 60)))
end
return cframe
end
function act_on_sudoku(sudoku_anim::SudokuAnim, action)
for i in 1:9
act!(sudoku_anim.cells[i, :], action)
end
act!(sudoku_anim.vlines, action)
act!(sudoku_anim.hlines, action)
end
function draw_arrows(cframe, nframes, sa1, grid; from_row=1)
row_possible = Vector{Vector{Int}}(undef, 9)
for j in 1:9
possible = compute_possible(grid, from_row, j)[1]
row_possible[j] = collect(possible)
end
arrows = Vector{Vector{Javis.Object}}(undef, 9)
arrow_mapping = zeros(Int, (9,9))
for j in 1:9
arrows[j] = Vector{Javis.Object}(undef, length(row_possible[j]))
for (i,d) in enumerate(row_possible[j])
arrows[j][i] = Object(cframe:nframes, (args...; t=0, linewidth=2)->arrow_line(2*sa1.size, sa1, from_row, j, d; t, linewidth))
arrow_mapping[j, d] = i
end
end
fstart = 1
for j in 1:9
for (i,d) in enumerate(row_possible[j])
act!(arrows[j][i], Action(fstart:fstart+29, sineio(), change(:t, 0 => 1)))
end
fstart += 35
end
cframe += fstart
return cframe, arrows, arrow_mapping
end
function draw_matching(sa, cframe, aframe, arrows, arrow_mapping, matching; color="#3C86F1", set_opacity=false)
color_anim = Animation(
[0, 1], # must go from 0 to 1
[Lab(colorant"white"), Lab(Base.parse(Colorant,color))],
[sineio()],
)
opacity_anim = Animation(
[0, 1], # must go from 0 to 1
[1, 0.7],
[sineio()],
)
opacity_back_anim = Animation(
[0, 1], # must go from 0 to 1
[0.7, 1.0],
[sineio()],
)
fstart = aframe
used = zeros(Int, 9)
for (index,p) in enumerate(matching)
f = first(p)
t = arrow_mapping[f,last(p)]
used[f] = t
act!(arrows[f][t], Action(fstart:fstart+20, color_anim, sethue()))
act!(arrows[f][t], Action(fstart:fstart+5, change(:linewidth, 2=>4)))
if set_opacity
act!(arrows[f][t], Action(fstart:fstart+5, opacity_back_anim, setopacity()))
end
act!(sa.cells[:, f], Action(cframe+5:cframe+5, change(:extra, last(p))))
fstart += 25
cframe += 25
end
for f in 1:9
for t in 1:length(arrows[f])
t == used[f] && continue
act!(arrows[f][t], Action(fstart:fstart+15, change(:linewidth, 2=>1)))
act!(arrows[f][t], Action(fstart:fstart+15, opacity_anim, setopacity()))
end
end
fstart += 50
cframe += 50
for f in 1:9
act!(sa.cells[:, f], Action(cframe+5:cframe+5, change(:extra, -1)))
for t in 1:length(arrows[f])
t == used[f] && continue
act!(arrows[f][t], Action(fstart:fstart+15, change(:linewidth, 1=>2)))
act!(arrows[f][t], Action(fstart:fstart+15, opacity_back_anim, setopacity()))
end
end
return fstart-aframe
end
function draw_cycle(aframe, arrows, arrow_mapping, cycle; step_anim=true)
color_anim_cycle_normal = Animation(
[0, 1], # must go from 0 to 1
[Lab(colorant"white"), Lab(colorant"#BBFF4B")],
[sineio()],
)
color_anim_cycle_blue = Animation(
[0, 1], # must go from 0 to 1
[Lab(colorant"#3C86F1"), Lab(colorant"#BBFF4B")],
[sineio()],
)
opacity_anim = Animation(
[0, 1], # must go from 0 to 1
[0.7, 1.0],
[sineio()],
)
fstart = aframe
down = true
for index in 1:length(cycle)-1
cycle[index] == 0 && continue
cycle[index+1] == 0 && continue
if down
f = cycle[index]
t = arrow_mapping[f,cycle[index+1]]
else
f = cycle[index+1]
t = arrow_mapping[f,cycle[index]]
end
if !down
color_anim = color_anim_cycle_normal
act!(arrows[f][t], Action(fstart:fstart+5, change(:linewidth, 2=>4)))
else
color_anim = color_anim_cycle_blue
end
act!(arrows[f][t], Action(fstart:fstart+20, color_anim, sethue()))
act!(arrows[f][t], Action(fstart:fstart+20, opacity_anim, setopacity()))
step_anim && (fstart += 25)
down = !down
end
return fstart-aframe
end
function reset_cycle(aframe, arrows, arrow_mapping, cycle)
color_anim_cycle_normal = Animation(
[0, 1], # must go from 0 to 1
[Lab(colorant"#BBFF4B"), Lab(colorant"white")],
[sineio()],
)
color_anim_cycle_blue = Animation(
[0, 1], # must go from 0 to 1
[Lab(colorant"#BBFF4B"), Lab(colorant"#3C86F1")],
[sineio()],
)
opacity_anim = Animation(
[0, 1], # must go from 0 to 1
[1.0, 0.7],
[sineio()],
)
fstart = aframe
down = true
for index in 1:length(cycle)-1
cycle[index] == 0 && continue
cycle[index+1] == 0 && continue
if down
f = cycle[index]
t = arrow_mapping[f,cycle[index+1]]
else
f = cycle[index+1]
t = arrow_mapping[f,cycle[index]]
end
if !down
color_anim = color_anim_cycle_normal
act!(arrows[f][t], Action(fstart:fstart+5, change(:linewidth, 4=>2)))
else
color_anim = color_anim_cycle_blue
end
act!(arrows[f][t], Action(fstart:fstart+20, color_anim, sethue()))
act!(arrows[f][t], Action(fstart:fstart+20, opacity_anim, setopacity()))
down = !down
end
return fstart-aframe
end
function reset_matching(aframe, arrows, arrow_mapping, matching; color="#3C86F1")
color_anim = Animation(
[0, 1], # must go from 0 to 1
[Lab(Base.parse(Colorant,color)), Lab(colorant"white")],
[sineio()],
)
for p in matching
f = first(p)
t = arrow_mapping[f,last(p)]
act!(arrows[f][t], Action(aframe:aframe+20, color_anim, sethue()))
act!(arrows[f][t], Action(aframe:aframe+5, change(:linewidth, 4=>2)))
end
end
function main(;stream=true)
video = Video(1920, 1080)
nframes = 4500
sudoku_grid = [
0 0 0 5 4 6 0 0 9;
0 2 0 0 0 0 0 0 7;
0 0 3 9 0 0 0 0 4;
9 0 5 0 0 0 0 7 0;
7 0 0 0 0 0 0 2 0;
0 0 0 0 9 3 0 0 0;
0 5 6 0 0 8 0 0 0;
0 1 0 0 3 9 0 0 0;
0 0 0 0 0 0 8 0 6;
]
sudoku_possible = Array{Set{Int}}(undef, (9,9))
for i=1:9, j=1:9
sudoku_possible[i,j] = Set{Int}()
end
Background(1:nframes, ground)
size_sudoku = 750
xoffset = 700
yoffset = 150
title = Object(1:100, show_title)
act!(title, Action(1:15, appear(:fade)))
act!(title, Action(85:100, disappear(:fade)))
grid_start = 100
line_objects = get_line_objects(grid_start:nframes, size_sudoku; anim_draw_len=30, xoffset, yoffset)
so, cso = create_sudoku_objects(grid_start:nframes, size_sudoku; xoffset, yoffset)
sudoku_anim = SudokuAnim(size_sudoku, xoffset, yoffset,
line_objects.vlines,
line_objects.hlines,
so)
subtitle = Object(grid_start:nframes, (args...; s="", fsize=50)->show_subtitle(args...; s, fsize))
cframe = 0
cframe += 60
set_sudoku_grid(so, sudoku_grid; framestart=60, anim_draw_len=20)
set_subtitle!(subtitle, cframe, "Sudoku"; len=30, fsize=75)
cframe += 30
set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; is=1, js=1, framestart=cframe+10, anim_draw_len=20, parts=[])
set_subtitle!(subtitle, cframe, "Fill cell with values"; len=50)
cframe += 50
set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; is=1, js=1, framestart=cframe+10, anim_draw_len=0, parts=[:row])
set_subtitle!(subtitle, cframe, "Eliminating row values"; len=50)
cframe += 50
set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; is=1, js=1, framestart=cframe+10, anim_draw_len=0, parts=[:row, :col])
set_subtitle!(subtitle, cframe, "Eliminating column values"; len=50)
cframe += 50
set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; is=1, js=1, framestart=cframe+10, anim_draw_len=0, parts=[:row, :col, :block])
set_subtitle!(subtitle, cframe, "Eliminating block values"; len=50)
cframe += 50
set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; is=2:3, js=1:3, framestart=cframe+10, anim_draw_len=20)
set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; is=1:3, js=2:3, framestart=cframe+10, anim_draw_len=20)
set_subtitle!(subtitle, cframe, "Repeating for whole block"; len=50)
cframe += 100
set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; is=4:9, js=1:9, framestart=cframe+10, anim_draw_len=20)
set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; is=1:9, js=4:9, framestart=cframe+10, anim_draw_len=20)
set_subtitle!(subtitle, cframe, "Repeating for whole Sudoku"; len=50)
subtitle_size = 50
cframe += 50
set_subtitle!(subtitle, cframe, "Fix cells where only one value is possible"; len=100, fsize=subtitle_size)
changed = set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; framestart=cframe+40, anim_draw_len=0, fixing=true, just_fixing=true)
show_changed(cso, changed, cframe; len=90, anim_length=30)
cframe += 100
set_subtitle!(subtitle, cframe, "Updating the row column and block"; len=100, fsize=subtitle_size)
changed = set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; framestart=cframe+40, anim_draw_len=0)
show_changed(cso, changed, cframe; len=90, anim_length=15)
cframe += 100
set_subtitle!(subtitle, cframe, "Fixing again"; len=100, fsize=subtitle_size)
changed = set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; framestart=cframe+40, anim_draw_len=0, fixing=true, just_fixing = true)
show_changed(cso, changed, cframe; len=90, anim_length=15)
cframe += 100
set_subtitle!(subtitle, cframe, "Updating"; len=100, fsize=subtitle_size)
changed = set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; framestart=cframe+40, anim_draw_len=0)
show_changed(cso, changed, cframe; len=90, anim_length=15)
cframe += 100
set_subtitle!(subtitle, cframe, "And fixing"; len=100, fsize=subtitle_size)
changed = set_sudoku_immediate_impossible(so, sudoku_grid, sudoku_possible; framestart=cframe+40, anim_draw_len=0, fixing=true, just_fixing = true)
show_changed(cso, changed, cframe; len=90, anim_length=15)
cframe = focus_on_row(grid_start, cframe+100, 3, sudoku_anim, subtitle, subtitle_size)
cframe += 100
line_objects_2 = get_line_objects(grid_start+cframe:nframes, size_sudoku; anim_draw_len=0, xoffset, yoffset)
so_2, _ = create_sudoku_objects(grid_start+cframe:nframes, size_sudoku; xoffset, yoffset)
grid_start_2 = grid_start+cframe
sudoku_grid_2 = zeros(Int, (9,9))
sudoku_grid_2[6,:] = 1:9
set_sudoku_grid(so_2, sudoku_grid_2; framestart=1, anim_draw_len=0)
sudoku_anim_2 = SudokuAnim(size_sudoku, xoffset, yoffset,
line_objects_2.vlines,
line_objects_2.hlines,
so_2)
focus_on_row(grid_start, 1, 6, sudoku_anim_2, subtitle, subtitle_size; shift=:down, mark_row=false, do_anim=false)
act_on_sudoku(sudoku_anim_2, Action(1:30, appear(:fade)))
cframe += 30
@show grid_start+cframe
sframe, arrows, arrow_mapping = draw_arrows(grid_start+cframe, nframes, sudoku_anim, sudoku_grid; from_row = 3)
matching_1 = [1=>1, 2=>6, 3=>3, 4=>9, 5=>2, 6=>7, 7=>5, 8=>8, 9=>4]
matching_start = sframe-cframe
@show matching_start
cframe = sframe
frames_used = draw_matching(sudoku_anim, cframe, matching_start, arrows, arrow_mapping, matching_1)
cframe += 90
cframe += frames_used
@show grid_start_2
@show frames_used
act_on_sudoku(sudoku_anim_2, Action(GFrames(grid_start+cframe+30:grid_start+cframe+60), sineio(), anim_translate(220, 0)))
act_on_sudoku(sudoku_anim, Action(cframe+30:cframe+60, sineio(), anim_translate(220, 0)))
cframe += 60
berge = Object(grid_start+cframe+30:nframes, show_berge)
cycle_1 = [2,6,7,5,8,8,2]
cycle_start = matching_start+frames_used+350
opacity_anim = Animation(
[0, 1], # must go from 0 to 1
[1, 0.7],
[sineio()],
)
for i in 1:9
act!(arrows[i], Action(cycle_start-30:cycle_start-15, opacity_anim, setopacity()))
end
frames_used = draw_cycle(cycle_start, arrows, arrow_mapping, cycle_1)
reset_cycle(cycle_start+frames_used+100, arrows, arrow_mapping, cycle_1)
cycle_2 = [1,1,8,8,2,6,1]
cycle_start = cycle_start+frames_used+150
frames_used = draw_cycle(cycle_start, arrows, arrow_mapping, cycle_2)
reset_cycle(cycle_start+frames_used+100, arrows, arrow_mapping, cycle_2)
cycle_3 = [1,1,7,5,1]
cycle_start = cycle_start+frames_used+150
frames_used = draw_cycle(cycle_start, arrows, arrow_mapping, cycle_3)
reset_cycle(cycle_start+frames_used+100, arrows, arrow_mapping, cycle_3)
cycle_4 = [5,2,6,7,5]
cycle_start = cycle_start+frames_used+150
frames_used = draw_cycle(cycle_start, arrows, arrow_mapping, cycle_4)
reset_cycle(cycle_start+frames_used+100, arrows, arrow_mapping, cycle_4)
cycle_5 = [2,6,8,8,2]
cycle_start = cycle_start+frames_used+150
frames_used = draw_cycle(cycle_start, arrows, arrow_mapping, cycle_5)
reset_cycle(cycle_start+frames_used+100, arrows, arrow_mapping, cycle_5)
cycle_6 = [1,1,8,8,1]
cycle_start = cycle_start+frames_used+150
frames_used = draw_cycle(cycle_start, arrows, arrow_mapping, cycle_6)
reset_cycle(cycle_start+frames_used+100, arrows, arrow_mapping, cycle_6)
cycle_7 = [cycle_1..., 0, cycle_2..., 0, cycle_3..., 0, cycle_4..., 0, cycle_5..., 0, cycle_6...]
cycle_start = cycle_start+frames_used+150
frames_used = draw_cycle(cycle_start, arrows, arrow_mapping, cycle_7; step_anim=false)
reset_cycle(cycle_start+frames_used+100, arrows, arrow_mapping, cycle_7)
reset_matching(cycle_start+frames_used+100, arrows, arrow_mapping, matching_1)
remove_1 = [2=>7, 7=>2]
@show cframe+150*12
frames_used = draw_matching(sudoku_anim, cframe+150*12+50, 2690, arrows, arrow_mapping, remove_1; color="#F74BFF", set_opacity=true)
act!(so[3,2], Action(GFrames(4350:nframes), change(:numbers, [6,8])))
act!(so[3,7], Action(GFrames(4350:nframes), change(:numbers, [1,5,6])))
act!(arrows[2][2], Action(GFrames(4350:4380), disappear(:fade)))
act!(arrows[7][arrow_mapping[7,2]], Action(GFrames(4350:4380), disappear(:fade)))
# streamconfig = setup_stream(; address="0.0.0.0", port=14015)
if stream
render(video; pathname="sudoku.gif", streamconfig)
else
render(video; pathname="sudoku.mp4")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment