-
-
Save Wikunia/a708ab1de757b4918e31588a96646e17 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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