-
-
Save YoOoster/8ea3644bb24c531271188fa40c90879b to your computer and use it in GitHub Desktop.
Solves sudoku and image jigsaw puzzles created by http://flash-gear.com/puzzle/ and https://www.jigidi.com/
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
use 5.012; | |
use strict; | |
use warnings; | |
use File::Temp qw(tempfile); | |
use IPC::System::Simple qw(capture system); | |
use LWP::UserAgent; | |
use URI::QueryParam; | |
use Win32::GUI; | |
use Data::Dumper; | |
use integer; | |
use constant false => 0; | |
use constant true => 1; | |
my $PicJigsaw = Win32::GUI::Bitmap->new("jigsaw.bmp"); | |
my $PicSudoku = Win32::GUI::Bitmap->new("sudoku.bmp"); | |
my @board; | |
my $solveCount = 0; | |
my $Window_Main; | |
my $Window_Jigsaw; | |
my $Window_Sudoku; | |
######################################################### | |
# Main Window # | |
######################################################### | |
sub Create_Window_Main { | |
my $W1 = Win32::GUI::Window->new( | |
-name => "WindowMain", | |
-title => "Depuzzlefy", | |
-size => [ 800, 475 ], | |
-pos => [ Win32::GUI::Width(Win32::GUI::GetDesktopWindow())/2-400, Win32::GUI::Height(Win32::GUI::GetDesktopWindow())/2-237.50 ], | |
-sizable => 0, | |
-hasmaximize => 0, | |
-maximizebox => 0, | |
-hasminimize => 0, | |
-minimizebox => 0, | |
); | |
$W1->AddButton( | |
-name => "ButtonMainJigsaw", | |
-text => "Jigsaw puzzles", | |
-align => "center", | |
-valign => "center", | |
-picture=> $PicJigsaw, | |
-pos => [ 25, 60 ], | |
-size => [ 350, 350], | |
); | |
$W1->AddButton( | |
-name => "ButtonMainSudoku", | |
-text => "Sudoku", | |
-align => "center", | |
-valign => "center", | |
-picture=> $PicSudoku, | |
-pos => [ 400, 60 ], | |
-size => [ 350, 350], | |
); | |
$W1->AddLabel( | |
-name => "LabelMainJigsaw", | |
-text => "Jigsaw Puzzles", | |
-pos => [175, 45], | |
-size => [350, 15], | |
); | |
$W1->AddLabel( | |
-name => "LabelMainSudoku", | |
-text => "Sudoku", | |
-pos => [550, 45], | |
-size => [350, 15], | |
); | |
return $W1; | |
} | |
sub WindowMain_Terminate { | |
return -1; | |
} | |
sub ButtonMainJigsaw_Click { | |
$Window_Main->Hide(); | |
$Window_Jigsaw->DoModal(); | |
} | |
sub ButtonMainSudoku_Click { | |
$Window_Main->Hide(); | |
$Window_Sudoku->DoModal(); | |
} | |
######################################################### | |
# Jigsaw Window # | |
######################################################### | |
sub Create_Window_Jigsaw { | |
my $W1 = Win32::GUI::Window->new( | |
-name => "WindowJigsaw", | |
-title => "Depuzzlefy - Jigsaw", | |
-size => [ 300, 150 ], | |
-pos => [ Win32::GUI::Width(Win32::GUI::GetDesktopWindow())/2-150, Win32::GUI::Height(Win32::GUI::GetDesktopWindow())/2-75 ], | |
-sizable=> 0, | |
-parent => $Window_Main, | |
-hasmaximize => 0, | |
-maximizebox => 0, | |
-hasminimize => 0, | |
-minimizebox => 0, | |
); | |
$W1->AddButton( | |
-name => "ButtonWJDepuzzlefy", | |
-text => "Depuzzlefy", | |
-pos => [ 20, 60 ], | |
-size => [ 250, 30], | |
); | |
$W1->AddLabel( | |
-name => "LabelWJUrl", | |
-text => "Insert URL", | |
-pos => [20, 20], | |
-size => [250, 20], | |
); | |
$W1->AddTextfield( | |
-name => "TextfieldWJUrl", | |
-pos => [20,40], | |
-size => [250, 20], | |
); | |
return $W1; | |
} | |
sub WindowJigsaw_Terminate { | |
$Window_Main->Show(); | |
return -1; | |
} | |
sub ButtonWJDepuzzlefy_Click { | |
my $url = $Window_Jigsaw->TextfieldWJUrl->Text(); | |
if ($url =~ m[flash-gear.com]gi) { | |
FlashGearRequest(); | |
} elsif ($url =~ m[jigidi.com]gi) { | |
JigidiRequest(); | |
} else { | |
$Window_Jigsaw->TextfieldWJUrl->SelectAll(); | |
$Window_Jigsaw->TextfieldWJUrl->Clear(); | |
print "Website isn't supported.'\n\n"; | |
return; | |
} | |
} | |
######################################################### | |
# Sudoku Window # | |
######################################################### | |
sub Create_Window_Sudoku { | |
my $W1 = Win32::GUI::Window->new( | |
-name => "WindowSudoku", | |
-title => "Depuzzlefy - Sudoku", | |
-size => [ 315, 370 ], | |
-pos => [ Win32::GUI::Width(Win32::GUI::GetDesktopWindow())/2-157.5, Win32::GUI::Height(Win32::GUI::GetDesktopWindow())/2-185 ], | |
-sizable => 0, | |
-parent => $Window_Main, | |
-hasmaximize => 0, | |
-maximizebox => 0, | |
-hasminimize => 0, | |
-minimizebox => 0, | |
); | |
for (my $i = 0; $i < 9; $i++) { | |
for (my $j = 0; $j <9; $j++) { | |
my $tf = $W1->AddTextfield( | |
-name => "TextFieldSudoku$i$j", | |
-pos => [($j*30)+20, ($i*30)+30], | |
-size => [25,25], | |
-align => "center", | |
-number => 1, | |
); | |
$tf->MaxLength(1); | |
} | |
} | |
$W1->AddButton( | |
-name => "ButtonSudokuSolve", | |
-text => "Solve", | |
-pos => [ 120, 295 ], | |
-size => [ 85, 30 ], | |
); | |
return $W1; | |
} | |
sub WindowSudoku_Terminate { | |
$Window_Main->Show(); | |
return -1; | |
} | |
sub ButtonSudokuSolve_Click { | |
undef @board; | |
$solveCount = 0; | |
for (my $i = 0; $i < 9; $i++) { | |
for (my $j = 0; $j < 9; $j++) { | |
my $method = "TextFieldSudoku$i$j"; | |
if (($Window_Sudoku->$method->Text() + 0) != "") { | |
push @board, (($Window_Sudoku->$method->Text()) + 0); | |
} else { | |
push @board, 0; | |
} | |
} | |
} | |
SolveSudoku(); | |
} | |
######################################################### | |
sub SolveSudoku { | |
printf "Trying to solve Sudoku. Count:%s\n", $solveCount++; | |
my $i; | |
foreach $i ( 0 .. 80 ) { | |
next if $board[$i]; | |
my %t = map { | |
$_ / 9 == $i / 9 || | |
$_ % 9 == $i % 9 || | |
$_ / 27 == $i / 27 && $_ % 9 / 3 == $i % 9 / 3 | |
? $board[$_] : 0, | |
1; | |
} 0 .. 80; | |
SolveSudoku( $board[$i] = $_ ) for grep !$t{$_}, 1 .. 9; | |
return $board[$i] = 0; | |
} | |
# $i = 0; | |
# foreach (@board) { | |
# print "-----+-----+-----\n" if !($i%27) && $i; | |
# print !($i%9) ? '': $i%3 ? ' ' : '|', $_; | |
# print "\n" unless ++$i%9; | |
# } | |
for (my $i = 0; $i < 9; $i++) { | |
for (my $j = 0; $j < 9; $j++) { | |
my $method = "TextFieldSudoku$i$j"; | |
my $value = $board[($i * 9) + $j]; | |
$Window_Sudoku->$method->SelectAll(); | |
$Window_Sudoku->$method->Clear(); | |
$Window_Sudoku->$method->Append("$value"); | |
} | |
} | |
} | |
sub ClearHideJigsaw { | |
$Window_Jigsaw->TextfieldWJUrl->SelectAll(); | |
$Window_Jigsaw->TextfieldWJUrl->Clear(); | |
$Window_Jigsaw->Hide(); | |
} | |
sub SetUserAgent { | |
my $ua = LWP::UserAgent->new(); | |
$ua->agent('Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0'); | |
$ua->cookie_jar({}); | |
$ua->protocols_allowed(['http','https']); | |
$ua->ssl_opts(verify_hostname => 0); | |
$ua->default_header('Accept-Encoding' => scalar HTTP::Message::decodable()); | |
return $ua; | |
} | |
# TODO: Find a way to make use of the normal temp map. using c:/dpf but this map is getting deleted at the end. Might be troublesome if someone made a own map. | |
# Using c:/dpf because otherwise large puzzles were getting errors because of too long commandprompt commands. | |
# This may still happen on really large puzzles but I haven't encountered them yet. | |
sub FlashGearRequest { | |
my $url = $Window_Jigsaw->TextfieldWJUrl->Text(); | |
ClearHideJigsaw(); | |
print "Requesting URL data\n\n"; | |
my $ua = SetUserAgent(); | |
my $res = $ua->get($url); | |
if(!$res->is_success) { | |
printf "%s\n\n", $res->status_line; | |
$Window_Jigsaw->Show(); | |
return; | |
} | |
my $content = $res->decoded_content // $res->content // die 'no content'; | |
my @url = $content =~ m[<embed(?: [^>]*?)? src="([^"]+)"]gi; | |
if(!@url) { | |
print "No Flash file found. Please insert a correct URL\n\n"; | |
$Window_Jigsaw->Show(); | |
return; | |
} | |
print "Found Flash file\n\n"; | |
print "Extracting pictures from the Flash file\n"; | |
print "This may take a while depending on the size of the puzzle\n\n"; | |
my $dir = "C:\\dpf"; | |
my $img = ''; | |
$url = $url[1]; | |
my $uri = URI->new($url); | |
my ($h, $w, $id) = map $uri->query_param($_), qw(h w id); | |
next unless $h and $w and $id; | |
$uri->query_param(c => 'z'); | |
my $swf = File::Temp->new(suffix => '.swf'); | |
$res = $ua->get($uri, ':content_file' => $swf->filename); | |
my $out = capture swfextract => $swf; | |
my ($ids) = $out =~ /^\s*\[-j\] \d+ JPEGs: ID\(s\) (\d+,.*)/m; | |
my @ids = split(", ", $ids); | |
mkdir $dir, 0666; | |
foreach my $id (@ids) { | |
system swfextract => '-j', $id, '--outputformat', "$dir/%05d.%s", $swf; | |
} | |
# FIX: Other jpgs will crash it. | |
my @jpg = glob "$dir/*.jpg"; | |
$out = capture identify => $jpg[0]; | |
my ($x, $y) = $out =~ / JPEG (\d+)x(\d+)/; | |
next unless $x and $y and $x == $y; | |
$_ = int $_ / $x * 2 for $w, $h; | |
# The edges of each puzzle piece image need to be overlapped. | |
$_ = int $_ / 4 for $x, $y; | |
$img = "$id.jpg"; | |
system montage => '-tile', "${w}x$h", '-geometry', "-$x-$y", @jpg, $img; | |
unlink @jpg; | |
system "cmd /c start $img"; | |
print "Done\n\n"; | |
$Window_Jigsaw->Show(); | |
} | |
sub JigidiRequest { | |
my $url = $Window_Jigsaw->TextfieldWJUrl->Text(); | |
ClearHideJigsaw(); | |
my @id = $url =~ m[\?id=([^"]+)]; | |
print "Requesting URL data\n\n"; | |
my $ua = SetUserAgent(); | |
my $res = $ua->get($url); | |
if(!$res->is_success) { | |
printf "%s\n\n", $res->status_line; | |
$Window_Jigsaw->Show(); | |
return; | |
} | |
my $content = $res->decoded_content // $res->content // die 'no content\n'; | |
my @token = $content =~ m[token:\"([^"]+)]; | |
printf "%s\n\n", "Found token"; | |
$res = $ua->get("https://www.jigidi.com/ajax/api/2/game_lookup.php?token=$token[0]"); | |
if(!$res->is_success) { | |
printf "%s\n\n", $res->status_line; | |
$Window_Jigsaw->Show(); | |
return; | |
} | |
$content = $res->decoded_content // $res->content // die 'no content\n'; | |
my @pic = $content =~ m[image\":\"([^"]+)]; | |
$pic[0] =~ s/[\\]//g ; | |
$pic[0] =~ s/.{5}$//; | |
print "Saving picture\n\n"; | |
unlink "$id[0].jpg"; | |
$res = $ua->mirror($pic[0], "$id[0].jpg"); | |
unless($res->is_success) { | |
printf "%s\n\n", $res->status_line; | |
$Window_Jigsaw->Show(); | |
return; | |
} | |
system "cmd /c start $id[0].jpg"; | |
print "Done\n\n"; | |
$Window_Jigsaw->Show(); | |
} | |
$Window_Main = Create_Window_Main(); | |
$Window_Jigsaw = Create_Window_Jigsaw(); | |
$Window_Sudoku = Create_Window_Sudoku(); | |
$Window_Main->Show(); | |
Win32::GUI::Dialog(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Apart from the completion message which many people have already asked for, I'd very much like a non-windows option.