-
-
Save YoOoster/8ea3644bb24c531271188fa40c90879b to your computer and use it in GitHub Desktop.
| 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(); |
Updated the program. Link
- It now gets the high definition picture of jigidi puzzles.
- I'm still figuring out how to get the completion message
- I added a sudoku solver. Some sudoku might not be solvable by it.
I'll wait if there is a chance to get the completion message in jigidi too. Thank you!
I have the same problems as Rhoenbussard.
The puzzles always split in two files xxxx-0 and xxxx-1.
Followed by the error code that it can#T find the file withe the name xxxx.
Thanks for your help!
Kai
@kaischmitt
Which puzzle?
This:
http://four.flash-gear.com/npuz/puz.php?c=v&id=4103396&k=7328868
gives theese files:


I have the same problem with this URL: http://six.flash-gear.com/npuz/puz.php?c=v&id=3544876&k=77212470.
I've installed the latest version on the latest version of Windows10. Maybe that helps a little.
Super Tool! I am also interested in a completion message. Is there any posibility?
Super Tool! I am also interested in a completion message. Is there any posibility?
Ditto!
Apart from the completion message which many people have already asked for, I'd very much like a non-windows option.





Including the completion message would be very, very nice for me too!
Is there a possibility?