aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Krňávek <Jan.Krnavek@gmail.com>2020-11-15 09:04:35 +0100
committerJan Krňávek <Jan.Krnavek@gmail.com>2020-11-15 09:04:35 +0100
commite29dae3e932026fa0ef6c6f57dcb07fadd52856a (patch)
treeda329e425ba812ce122f3a112461780999514cf9
parentfe386961e5846533182f55716aa7156f34c070ed (diff)
parent4c31310c2fcdcc28b67276d0d5a90fdf820d8b48 (diff)
downloadperlweeklychallenge-club-e29dae3e932026fa0ef6c6f57dcb07fadd52856a.tar.gz
perlweeklychallenge-club-e29dae3e932026fa0ef6c6f57dcb07fadd52856a.tar.bz2
perlweeklychallenge-club-e29dae3e932026fa0ef6c6f57dcb07fadd52856a.zip
Merge remote-tracking branch 'upstream/master' into challenge-week-086
-rw-r--r--challenge-086/abigail/blog1.txt1
-rw-r--r--challenge-086/abigail/perl/ch-2.pl154
-rw-r--r--challenge-086/hstejas/README1
-rw-r--r--challenge-086/hstejas/cpp/ch-1.cpp43
-rw-r--r--challenge-086/hstejas/cpp/ch-2.cpp210
-rwxr-xr-xchallenge-086/hstejas/perl/ch-1.pl38
-rwxr-xr-xchallenge-086/hstejas/perl/ch-2.pl105
-rw-r--r--challenge-086/lubos-kolouch/perl/ch-1.pl48
-rw-r--r--challenge-086/lubos-kolouch/python/ch-1.py39
-rw-r--r--challenge-086/tyler-wardhaugh/clojure/src/tw/weekly/c86/t1.clj11
-rw-r--r--challenge-086/tyler-wardhaugh/lua/README.md1
-rwxr-xr-xchallenge-086/tyler-wardhaugh/lua/ch-1.lua28
-rwxr-xr-xchallenge-086/tyler-wardhaugh/lua/ch-2.lua250
-rwxr-xr-xchallenge-086/tyler-wardhaugh/lua/run.lua9
-rwxr-xr-xchallenge-086/tyler-wardhaugh/lua/test.lua23
-rw-r--r--members.json1
-rw-r--r--stats/pwc-current.json382
-rw-r--r--stats/pwc-language-breakdown-summary.json72
-rw-r--r--stats/pwc-language-breakdown.json1204
-rw-r--r--stats/pwc-leaders.json752
-rw-r--r--stats/pwc-summary-1-30.json104
-rw-r--r--stats/pwc-summary-121-150.json110
-rw-r--r--stats/pwc-summary-151-180.json106
-rw-r--r--stats/pwc-summary-181-210.json102
-rw-r--r--stats/pwc-summary-31-60.json40
-rw-r--r--stats/pwc-summary-61-90.json102
-rw-r--r--stats/pwc-summary-91-120.json104
-rw-r--r--stats/pwc-summary.json452
28 files changed, 2715 insertions, 1777 deletions
diff --git a/challenge-086/abigail/blog1.txt b/challenge-086/abigail/blog1.txt
new file mode 100644
index 0000000000..b97c4ee817
--- /dev/null
+++ b/challenge-086/abigail/blog1.txt
@@ -0,0 +1 @@
+https://wp.me/pcxd30-4C
diff --git a/challenge-086/abigail/perl/ch-2.pl b/challenge-086/abigail/perl/ch-2.pl
index 44646e9087..ecafa5924c 100644
--- a/challenge-086/abigail/perl/ch-2.pl
+++ b/challenge-086/abigail/perl/ch-2.pl
@@ -316,16 +316,58 @@ foreach my $x (@INDICES) {
}
-
################################################################################
#
-# Recursively solve the sudoku.
+# Two helper functions:
+# nr_of_elements: Given a bitfield, return how many elements it represents.
+# elements: Given a bitfield, return the elements it represents.
+#
+################################################################################
+
+my sub nr_of_elements ($bitfield) {
+ sprintf ("%b", $bitfield) =~ y/1/1/;
+}
+
+my sub elements ($bitfield) {
+ grep {$bitfield & (1 << ($_ - 1))} @ELEMENTS;
+}
+
+
+
+################################################################################
#
-# Given a set of solved and unsolved cells, pick a cell with the least
-# number of possibilities left. For each possibility, try this one, and
-# recurse. If any leads to a solution, return this. Else, return false,
-# so we can backtrack.
-# If the set of unsolved cells is empty, we have solved the complete sudoku.
+# Recursively solve the sudoku, given a set of solved cells, and a
+# set of unsolved cells.
+#
+# o If the set of unsolved cells is empty, we have solved the complete
+# sudoku, and we can return the set of solved cells.
+#
+# o If we have an unsolved cell with no possibilities left, there is no
+# solution possible, and we return 1.
+#
+# o If we have cells with one possibility left, then create a todo list
+# of all cells with one possibility left. Then, for each cell "c" of
+# the todo list:
+# - for each other unsolved cell "d" which "c" can see, remove "p"
+# from its set of possibilities.
+# + If, afterwards, "d" has no possibility left,
+# there is no solution.
+# + If, afterwards, "d" has one possibility left,
+# add it to the todo list.
+# - add "c" to the set of solved cells, with value "p"
+# - remove "c" from the set of unsolved cells, and from the todo list.
+#
+# o Otherwise, pick an unsolved cell "c" with the least number of possibilities
+# left (this will be at least two possibilities).
+# - for each of its possibilities "p":
+# + for each unsolved cell "d" which "c" can see, remove "p"
+# from its set of possibilites
+# + add "c" to the set of solved cells, with value "p"
+# + remove "c" from the set of unsolved cells.
+# + recurse:
+# = if there is a solution, return the solution
+# = else, try the next possibility
+# - if no possibility leads to a solution, there is no solution.
#
# For larger sudoku's, we can reach the "deep recursion" warning, so we
# silence it.
@@ -340,27 +382,89 @@ sub solve ($solved, $unsolved) {
return $solved unless keys %$unsolved;
#
- # Find the (a) square which the least possibilities; this
- # means finding the set with the least amount of bits set.
+ # Bucketize the set of unsolved cells, by the number
+ # of possibilities left.
+ #
+ my @buckets;
+ while (my ($key, $value) = each %$unsolved) {
+ push @{$buckets [nr_of_elements $value]} => $key;
+ }
+
+ #
+ # No solution possible.
+ #
+ return if $buckets [0];
+
+ if (@{$buckets [1] || []}) {
+ #
+ # We have unsolved cells with just one possibility left.
+ #
+ my %todo = map {$_ => 1} @{$buckets [1]};
+
+ #
+ # Make copies of the solved and unsolved structures.
+ #
+ my $new_solved = {%$solved};
+ my $new_unsolved = {%$unsolved};
+
+ while (keys %todo) {
+ my ($cell) = sort keys %todo;
+ my $mask = $$new_unsolved {$cell};
+ my ($x, $y) = split $; => $cell;
+
+ #
+ # For all unsolved cells which can be seen by this cell
+ # eliminate the value of this cell from its possibilities.
+ # If no possibilities are left, return undef. If one possibility
+ # is left, push onto @todo.
+ #
+ # In any case, move this cell from the set of unsolved cells
+ # to the set of solved cells.
+ #
+ foreach my $can_see (sees ($x, $y)) {
+ my ($x1, $y1) = @$can_see;
+ if ($$new_unsolved {$x1, $y1} &&
+ $$new_unsolved {$x1, $y1} & $mask) {
+ $$new_unsolved {$x1, $y1} &= ~ $mask;
+ my $nr_of_elements =
+ nr_of_elements $$new_unsolved {$x1, $y1};
+ return if $nr_of_elements == 0;
+ $todo {$x1, $y1} = 1 if $nr_of_elements == 1;
+ }
+ }
+
+ #
+ # Move cell to solved structure, and remove it from %todo.
+ #
+ $$new_solved {$cell} = (elements $mask) [0];
+ delete $$new_unsolved {$cell};
+ delete $todo {$cell};
+ }
+
+ #
+ # Recurse with the new sets
+ #
+ return solve ($new_solved, $new_unsolved);
+ }
+
+ #
+ # Now, find a cell with the least number of possibilities left.
+ # That will be a cell in the first non-empty bucket.
#
- my ($key) = map {$$_ [0]}
- sort {$$a [1] <=> $$b [1]}
- map {[$_, sprintf ("%b", $$unsolved {$_}) =~ y/1/1/]}
- keys %$unsolved;
- my ($x, $y) = split $; => $key;
- my $possibilities = $$unsolved {$key};
+ my ($bucket) = grep {$_} @buckets;
+ my $cell = $$bucket [0];
+ my ($x, $y) = split $; => $cell;
#
- # Guess each possibility for this key.
+ # Guess each possibility for this cell.
#
- foreach my $guess (@ELEMENTS) {
+ foreach my $guess (elements $$unsolved {$cell}) {
my $mask = 1 << ($guess - 1);
- next unless $possibilities & $mask;
#
# Create new solved unsolved structures, as copies from the given ones.
#
- my $new_solved = {%$solved};
+ my $new_solved = {%$solved};
my $new_unsolved = {%$unsolved};
#
@@ -371,16 +475,16 @@ sub solve ($solved, $unsolved) {
#
# Remove the guess from the set of unsolved cells.
#
- delete $$new_unsolved {$key};
+ delete $$new_unsolved {$cell};
#
- # Delete our guess as possibility for each square
+ # Delete our guess as possibility for each cell
# which can be seen.
#
foreach my $can_see (sees ($x, $y)) {
- my ($x, $y) = @$can_see;
- if ($$new_unsolved {$x, $y}) {
- $$new_unsolved {$x, $y} &= ~ $mask;
+ my ($x1, $y1) = @$can_see;
+ if ($$new_unsolved {$x1, $y1}) {
+ $$new_unsolved {$x1, $y1} &= ~ $mask;
}
}
@@ -419,7 +523,7 @@ if (my $r = solve ($solved, $unsolved)) {
}
}
else {
- say "No solution found\n";
+ say "No solution found.";
}
diff --git a/challenge-086/hstejas/README b/challenge-086/hstejas/README
new file mode 100644
index 0000000000..969c5c0569
--- /dev/null
+++ b/challenge-086/hstejas/README
@@ -0,0 +1 @@
+Solution by Tejas
diff --git a/challenge-086/hstejas/cpp/ch-1.cpp b/challenge-086/hstejas/cpp/ch-1.cpp
new file mode 100644
index 0000000000..79fa9a55bc
--- /dev/null
+++ b/challenge-086/hstejas/cpp/ch-1.cpp
@@ -0,0 +1,43 @@
+#include <iostream>
+#include <algorithm>
+#include <vector>
+
+// g++ --std=c++17 c1.cpp && ./a.out
+
+void pair_diff(unsigned int reference, std::vector<int> nums)
+{
+ std::sort(nums.begin(), nums.end(), std::greater<int>());
+ auto start = nums.begin();
+ auto curr = start;
+ while(start != nums.end() && curr != nums.end())
+ {
+ ++curr;
+ int diff = std::abs(*start - *curr);
+ if(diff == reference)
+ {
+ std::cout << "1 as " << *start << " - " << *curr << " = " << diff << std::endl;
+ return;
+ }
+ else if (diff > reference)
+ {
+ ++start;
+ curr = start;
+ }
+ }
+ std::cout << "0" << std::endl;
+}
+
+int main()
+{
+ std::vector<std::pair< int, std::vector<int>>> tests {
+ {7, {50, 8, 12, 15, 5} },
+ {6, {1, 5, 2, 9, 7} },
+ {15, {10, 30, 20, 50, 40} },
+ {15, {-15, -5, -30, 20, 50, 40} }
+ };
+
+ for (auto test : tests)
+ {
+ pair_diff(test.first, test.second);
+ }
+} \ No newline at end of file
diff --git a/challenge-086/hstejas/cpp/ch-2.cpp b/challenge-086/hstejas/cpp/ch-2.cpp
new file mode 100644
index 0000000000..534a5f036b
--- /dev/null
+++ b/challenge-086/hstejas/cpp/ch-2.cpp
@@ -0,0 +1,210 @@
+#include <array>
+#include <vector>
+#include <set>
+#include <iostream>
+#include <utility>
+
+// https://raw.githubusercontent.com/agauniyal/rang/master/include/rang.hpp
+#include "rang.hpp"
+
+// g++ --std=c++17 c2.cpp -O2 && ./a.out
+
+namespace std
+{
+ std::string to_string(bool in)
+ {
+ return in ? "true" : "false";
+ }
+} // namespace std
+
+class Board
+{
+public:
+
+ Board(const std::array<std::array<int, 9>, 9>& in)
+ :mBoard(in) { }
+
+ void fill(int* in)
+ {
+ for(size_t row = 0; row < mBoard.size(); row++)
+ {
+ for(size_t col = 0; col < mBoard.size(); col++)
+ {
+ *(in + (mBoard.size() * row) + col) = mBoard[row][col];
+ }
+ }
+ }
+
+ void checkPrint(const std::array<std::array<int, 9>, 9>& ref)
+ {
+ for(size_t row=0; row < mBoard.size(); row++)
+ {
+ for(size_t col=0; col < mBoard.size(); col++)
+ {
+ if(mBoard[row][col] == ref[row][col])
+ {
+ std::cout << mBoard[row][col] << " ";
+ }
+ else
+ {
+ std::cout << rang::fg::red << mBoard[row][col] << rang::fg::reset << " ";
+ }
+ }
+ std::cout << std::endl;
+ }
+ }
+
+ void print()
+ {
+ for(size_t row=0; row < mBoard.size(); row++)
+ {
+ for(size_t col=0; col < mBoard.size(); col++)
+ {
+ if(mBoard[row][col] != 0)
+ {
+ std::cout << mBoard[row][col] << " ";
+ }
+ else
+ {
+ std::cout << rang::fg::red << mBoard[row][col] << rang::fg::reset << " ";
+ }
+ }
+ std::cout << std::endl;
+ }
+ }
+
+ bool solve()
+ {
+ bool result = solveNext(0, 0);
+ std::cout << "Solved? " << std::to_string(result) << std::endl;
+ return result;
+ }
+
+protected:
+
+ bool validRow(int num, size_t row)
+ {
+ return std::find(mBoard[row].begin(), mBoard[row].end(), num) == mBoard[row].end();
+ }
+
+ bool validCol(int num, size_t col)
+ {
+ // entire col
+ for(size_t irow = 0; irow < mBoard.size(); irow++)
+ {
+ if(mBoard[irow][col] == num)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool validBox(int num, size_t row, size_t col)
+ {
+ size_t oRow = 3 * (row / 3);
+ size_t oCol = 3 * (col / 3);
+ // entire box
+ for(size_t irow = oRow; irow < oRow+3; irow++)
+ {
+ if(std::find(mBoard[irow].begin() + oCol, mBoard[irow].begin() + oCol + 3, num)
+ != (mBoard[irow].begin() + oCol + 3))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool isValid(int num, size_t row, size_t col)
+ {
+ return validRow(num, row) && validCol(num, col) && validBox(num, row, col);
+ }
+
+ bool solveNext(size_t row, size_t col)
+ {
+ if(mBoard[row][col] == 0)
+ {
+ for(int num = 1; num <=9; num++)
+ {
+ if(isValid(num, row, col))
+ {
+ mBoard[row][col] = num;
+ size_t nextCol = col == 8 ? 0 : col+1;
+ size_t nextRow = col == 8 ? row + 1 : row;
+ if(nextRow == 9 || solveNext(nextRow, nextCol))
+ {
+ return true;
+ }
+ mBoard[row][col] = 0;
+ }
+ }
+ }
+ else
+ {
+ size_t nextCol = col == 8 ? 0 : col + 1;
+ size_t nextRow = col == 8 ? row + 1 : row;
+ if(nextRow == 9 || solveNext(nextRow, nextCol))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ std::array<std::array<int, 9>, 9> mBoard;
+};
+
+#ifdef BUILD_SHARED
+extern "C" {
+ bool solve(int *data)
+ {
+ std::array< std::array<int, 9>, 9> input;
+ for(size_t row = 0; row < input.size(); row++)
+ {
+ for(size_t col = 0; col < input.size(); col++)
+ {
+ input[row][col] = *(data + (row * input.size()) + col);
+ }
+ }
+
+ Board board(input);
+ board.print();
+ bool ret = board.solve();
+ board.print();
+ board.fill(data);
+ return ret;
+ }
+}
+#else
+int main()
+{
+ std::array< std::array<int, 9>, 9> solved {{
+ { 4, 3, 5, 2, 6, 9, 7, 8, 1 },
+ { 6, 8, 2, 5, 7, 1, 4, 9, 3 },
+ { 1, 9, 7, 8, 3, 4, 5, 6, 2 },
+ { 8, 2, 6, 1, 9, 5, 3, 4, 7 },
+ { 3, 7, 4, 6, 8, 2, 9, 1, 5 },
+ { 9, 5, 1, 7, 4, 3, 6, 2, 8 },
+ { 5, 1, 9, 3, 2, 6, 8, 7, 4 },
+ { 2, 4, 8, 9, 5, 7, 1, 3, 6 },
+ { 7, 6, 3, 4, 1, 8, 2, 5, 9 },
+ }};
+
+ std::array< std::array<int, 9>, 9> input {{
+ { 0, 0, 0, 2, 6, 0, 7, 0, 1 },
+ { 6, 8, 0, 0, 7, 0, 0, 9, 0 },
+ { 1, 9, 0, 0, 0, 4, 5, 0, 0 },
+ { 8, 2, 0, 1, 0, 0, 0, 4, 0 },
+ { 0, 0, 4, 6, 0, 2, 9, 0, 0 },
+ { 0, 5, 0, 0, 0, 3, 0, 2, 8 },
+ { 0, 0, 9, 3, 0, 0, 0, 7, 4 },
+ { 0, 4, 0, 0, 5, 0, 0, 3, 6 },
+ { 7, 0, 3, 0, 1, 8, 0, 0, 0 },
+ }};
+
+ Board board(input);
+ board.solve();
+ board.print();
+}
+#endif // BUILD_SHARED \ No newline at end of file
diff --git a/challenge-086/hstejas/perl/ch-1.pl b/challenge-086/hstejas/perl/ch-1.pl
new file mode 100755
index 0000000000..8c1e81a7ba
--- /dev/null
+++ b/challenge-086/hstejas/perl/ch-1.pl
@@ -0,0 +1,38 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use v5.30;
+
+sub pair_diff {
+ my $ref = abs(shift);
+ my @nums = sort { $b <=> $a } @{ shift @_ };
+
+ while(@nums) {
+ my $num = shift @nums;
+ foreach(@nums) {
+ my $diff = abs($num - $_);
+ if($diff == $ref) {
+ say "1 as $num - $_ = $ref";
+ return;
+ }
+ elsif($diff > $ref) {
+ last;
+ }
+ }
+ }
+ say '0';
+}
+
+my $tests = {
+ 'Test1' => { 'ref' => 7, 'arr' => [10, 8, 12, 15, 5] },
+ 'Test2' => { 'ref' => 6, 'arr' => [1, 5, 2, 9, 7] },
+ 'Test3' => { 'ref' => 15, 'arr' => [10, 30, 20, 50, 40] },
+ 'Test4' => { 'ref' => 15, 'arr' => [-15, -5, -30, 20, 50, 40] },
+ 'Test5' => { 'ref' => -15, 'arr' => [-15, -5, -30, 20, 50, 40] },
+ 'Test6' => { 'ref' => 1, 'arr' => [9, map { $_ * 10 } 1..900000 ] },
+};
+
+foreach(sort keys %{$tests}) {
+ my $test = $tests->{$_};
+ pair_diff($test->{'ref'}, $test->{'arr'});
+} \ No newline at end of file
diff --git a/challenge-086/hstejas/perl/ch-2.pl b/challenge-086/hstejas/perl/ch-2.pl
new file mode 100755
index 0000000000..a72ffa21ea
--- /dev/null
+++ b/challenge-086/hstejas/perl/ch-2.pl
@@ -0,0 +1,105 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use v5.30;
+
+# g++ --std=c++17 -DBUILD_SHARED ../cpp/c2.cpp -O2 -fPIC -shared -o sudoku.so
+use FFI::Platypus;
+
+# sudo apt install libgtk3-perl
+use Gtk3 -init;
+
+use Data::Dumper;
+
+
+my $ffi = FFI::Platypus->new( api => 1 );
+$ffi->lib('./sudoku.so');
+
+$ffi->attach( 'solve' => ['int[]'] => 'bool' );
+
+my @puzzle = ( '', '', '', 2, 6, '', 7, '', 1,
+ 6, 8, '', '', 7, '', '', 9, '',
+ 1, 9, '', '', '', 4, 5, '', '',
+ 8, 2, '', 1, '', '', '', 4, '',
+ '', '', 4, 6, '', 2, 9, '', '',
+ '', 5, '', '', '', 3, '', 2, 8,
+ '', '', 9, 3, '', '', '', 7, 4,
+ '', 4, '', '', 5, '', '', 3, 6,
+ 7, '', 3, '', 1, 8, '', '', '',);
+
+my $window = Gtk3::Window->new ('toplevel');
+$window->signal_connect (delete_event => sub { Gtk3->main_quit });
+$window->set_title("Sudoku Solver");
+$window->set_border_width(5);
+
+my $provider = Gtk3::CssProvider->new();
+my $screen = Gtk3::Gdk::Screen::get_default;
+Gtk3::StyleContext::add_provider_for_screen($screen, $provider, 600);
+$provider->load_from_data('#boxsep { margin: 5px;} #boardsep { margin: 8px; }');
+
+my @input_boxes;
+
+my $vbox = Gtk3::Box->new( 'vertical', 5 );
+$window->add($vbox);
+
+for my $row (0..8) {
+ if($row == 3 or $row == 6) {
+ my $sep = Gtk3::HSeparator->new;
+ $sep->set_name('boxsep');
+ $vbox->add($sep);
+ }
+
+ my $hbox = Gtk3::Box->new( 'horizontal', 5 );
+ $vbox->add($hbox);
+
+ for my $col (0..8) {
+ if($col == 3 or $col == 6) {
+ my $sep = Gtk3::VSeparator->new();
+ $sep->set_name('boxsep');
+ $hbox->add($sep);
+ }
+ my $cell = new Gtk3::Entry->new;
+ $cell->set_width_chars(2);
+ $cell->set_text($puzzle[$row*9 + $col]);
+ push @input_boxes, $cell;
+ $hbox->add($cell)
+ }
+}
+my $board_sep = Gtk3::HSeparator->new;
+$board_sep->set_name('boardsep');
+$vbox->add($board_sep);
+
+my $solve_btn = Gtk3::Button->new('Solve');
+$solve_btn->signal_connect (clicked => sub {
+ my @input_nums;
+ foreach(@input_boxes) {
+ my $text = $_->get_text();
+ push @input_nums, ($text ? $text : 0);
+ }
+ my $result = solve(\@input_nums);
+ if($result) {
+ for(my $i = 0; $i <= $#input_nums; $i++) {
+ $input_boxes[$i]->set_text($input_nums[$i]);
+ }
+ }
+ else {
+ my $error_dialog = Gtk3::MessageDialog->new($window, 'destroy-with-parent', 'error', 'ok', 'Error solving Sudoku');
+ $error_dialog->present();
+ $error_dialog->signal_connect( response => sub { $error_dialog->destroy() } );
+ }
+ });
+
+my $clear_btn = Gtk3::Button->new('Clear');
+$clear_btn->signal_connect (clicked => sub {
+ for(@input_boxes) {
+ $_->set_text('');
+ }
+ });
+
+my $buttons = Gtk3::HBox->new;
+$buttons->add($solve_btn);
+$buttons->add($clear_btn);
+$vbox->add($buttons);
+
+$window->show_all;
+Gtk3::main;
diff --git a/challenge-086/lubos-kolouch/perl/ch-1.pl b/challenge-086/lubos-kolouch/perl/ch-1.pl
new file mode 100644
index 0000000000..0603c9b929
--- /dev/null
+++ b/challenge-086/lubos-kolouch/perl/ch-1.pl
@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+#===============================================================================
+#
+# FILE: ch-1.pl
+#
+# USAGE: ./ch-1.pl
+#
+# DESCRIPTION: Perl Weekly Challenge 086
+# Task 1
+# Pair Difference
+#
+# AUTHOR: Lubos Kolouch
+# CREATED: 11/14/2020 01:27:06 PM
+#===============================================================================
+
+use strict;
+use warnings;
+use Data::Dumper;
+
+sub is_pair_difference {
+ my $data = shift;
+
+ # to avoid sorting and/or scanning through all pairs in the array
+ # or double nested loop,
+ # I will convert the array to a hash, then check if the
+ # corresponding key exists
+
+ my $arr = $$data{n};
+ my %h;
+ for (@$arr) {
+ $h{$_} = 1;
+ }
+
+ for my $x (keys %h) {
+ return 1 if $h{$x + $$data{a}};
+ }
+
+ return 0;
+}
+
+use Test::More;
+
+is(is_pair_difference( { 'n' => [10, 8, 12, 15, 5], 'a' => 7 }), 1);
+is(is_pair_difference( { 'n' => [1, 5, 2, 9, 7], 'a' => 6 }), 1);
+is(is_pair_difference( { 'n' => [10, 30, 20, 50, 40], 'a' => 15 }), 0);
+
+done_testing;
+
diff --git a/challenge-086/lubos-kolouch/python/ch-1.py b/challenge-086/lubos-kolouch/python/ch-1.py
new file mode 100644
index 0000000000..0f284bf4c6
--- /dev/null
+++ b/challenge-086/lubos-kolouch/python/ch-1.py
@@ -0,0 +1,39 @@
+#!env python
+"""
+#===============================================================================
+#
+# FILE: ch-1.py
+#
+# USAGE: ./ch-1.py
+#
+# DESCRIPTION: Perl Weekly Challenge 086
+# Task 1
+# Pair Difference
+#
+# AUTHOR: Lubos Kolouch
+# CREATED: 11/14/2020 01:27:06 PM
+#===============================================================================
+"""
+
+
+def is_pair_difference(n: list, a: int):
+ """
+ # to avoid sorting and/or scanning through all pairs in the array
+ # or double nested loop,
+ # I will convert the array to a hash, then check if the
+ # corresponding key exists
+ """
+
+ hash_keys = {}
+ for number in n:
+ hash_keys[number] = 1
+
+ for x in hash_keys:
+ if hash_keys.get(x+a, 0):
+ return 1
+ return 0
+
+
+assert is_pair_difference(n=[10, 8, 12, 15, 5], a=7) == 1
+assert is_pair_difference(n=[1, 5, 2, 9, 7], a=6) == 1
+assert is_pair_difference(n=[10, 30, 20, 50, 40], a=15) == 0
diff --git a/challenge-086/tyler-wardhaugh/clojure/src/tw/weekly/c86/t1.clj b/challenge-086/tyler-wardhaugh/clojure/src/tw/weekly/c86/t1.clj
index 4a6a873bc7..762e938629 100644
--- a/challenge-086/tyler-wardhaugh/clojure/src/tw/weekly/c86/t1.clj
+++ b/challenge-086/tyler-wardhaugh/clojure/src/tw/weekly/c86/t1.clj
@@ -8,12 +8,11 @@
(defn pair-difference
"Find a pair of coll such that their difference equals the target"
[target coll]
- (let [freqs (frequencies coll)
- s (-> freqs keys set)
- repeater (fn [v] (when v (repeat 2 v)))]
- (if (zero? target)
- (->> freqs (filter (fn [[_ v]] (> v 1))) ffirst repeater)
- (->> s (keep (fn [v] (let [k (+ target v)] (when (s k) [v k])))) first))))
+ (let [xf (if (zero? target)
+ (keep (fn [[k v]] (when (> v 1) k)))
+ (map key))
+ s (into #{} xf (frequencies coll))]
+ (->> s (filter #(s (+ target %))) first)))
(defn -main
"Run Task 1 with a target A and a list of numbers N, defaulting to the
diff --git a/challenge-086/tyler-wardhaugh/lua/README.md b/challenge-086/tyler-wardhaugh/lua/README.md
index 5a776b300d..ad70c646d1 100644
--- a/challenge-086/tyler-wardhaugh/lua/README.md
+++ b/challenge-086/tyler-wardhaugh/lua/README.md
@@ -21,3 +21,4 @@ Run the project's tests (all the samples from the task descriptions plus some ot
* [Lua](https://www.lua.org/) 5.3
* [LuaRocks](https://luarocks.org/)
* [busted](https://olivinelabs.com/busted/) (a unit testing framework)
+* [Moses](https://yonaba.github.io/Moses/) (a Lua utility-belt library)
diff --git a/challenge-086/tyler-wardhaugh/lua/ch-1.lua b/challenge-086/tyler-wardhaugh/lua/ch-1.lua
new file mode 100755
index 0000000000..8e9eda4572
--- /dev/null
+++ b/challenge-086/tyler-wardhaugh/lua/ch-1.lua
@@ -0,0 +1,28 @@
+#!/usr/bin/env lua
+
+local t1 = {}
+
+function t1.pair_difference(target, coll)
+ local freq = {}
+ for _, v in ipairs(coll) do freq[v] = (freq[v] or 0) + 1 end
+
+ for k, v in pairs(freq) do
+ if (freq[k + target]) and ((target ~= 0) or (v > 1)) then
+ return 1
+ end
+ end
+
+ return 0
+end
+
+function t1.run(args)
+ local target = tonumber(args[1])
+ table.remove(args, 1)
+
+ local coll = {}
+ for _, v in ipairs(args) do table.insert(coll, tonumber(v)) end
+
+ print(t1.pair_difference(target, coll))
+end
+
+return t1
diff --git a/challenge-086/tyler-wardhaugh/lua/ch-2.lua b/challenge-086/tyler-wardhaugh/lua/ch-2.lua
new file mode 100755
index 0000000000..2b3a453fdb
--- /dev/null
+++ b/challenge-086/tyler-wardhaugh/lua/ch-2.lua
@@ -0,0 +1,250 @@
+#!/usr/bin/env lua
+
+--[[
+ This is a Lua implementation of Peter Novig's excellent sudoku solver,
+ originally written in Python:
+ [Solving Every Sudoku Puzzle](http://norvig.com/sudoku.html)
+--]]
+
+local M = require('moses')
+
+local t2 = {}
+
+
+--[[ utility ]]--
+function t2.contains(tbl, elem)
+ for _, v in pairs(tbl) do
+ if v == elem then return true end
+ end
+ return false
+end
+
+function t2.slurp(input)
+ local fh = assert(io.open(input, "r"))
+ local text = fh:read("*all")
+ fh:close()
+ return text
+end
+
+function t2.deep_copy(tbl)
+ local copy = {}
+ for k, v in pairs(tbl) do
+ copy[k] = v
+ end
+ return copy
+end
+
+function t2.dict(tbl)
+ local result = {}