From 53ea7400f83c18278c85c96e5592af784705fe81 Mon Sep 17 00:00:00 2001 From: Paulo Custodio Date: Tue, 17 Sep 2024 10:13:26 +0100 Subject: Add Pythonsolution to challenge 286 --- challenge-286/paulo-custodio/python/ch-1.py | 36 +++++++++++ challenge-286/paulo-custodio/python/ch-2.py | 94 +++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 challenge-286/paulo-custodio/python/ch-1.py create mode 100644 challenge-286/paulo-custodio/python/ch-2.py diff --git a/challenge-286/paulo-custodio/python/ch-1.py b/challenge-286/paulo-custodio/python/ch-1.py new file mode 100644 index 0000000000..28e9703901 --- /dev/null +++ b/challenge-286/paulo-custodio/python/ch-1.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +# Challenge 286 +# +# Task 1: Self Spammer +# Submitted by: David Ferrone +# +# Write a program which outputs one word of its own script / source code at +# random. A word is anything between whitespace, including symbols. +# Example 1 +# +# If the source code contains a line such as: +# 'open my $fh, "<", "ch-1.pl" or die;' +# then the program would output each of the words { open, my, $fh,, "<",, +# "ch-1.pl", or, die; } +# (along with other words in the source) with some positive probability. +# +# Example 2 +# +# Technically 'print(" hello ");' is *not* an example program, because it does +# not assign positive probability to the other two words in the script. +# It will never display print(" or "); +# +# Example 3 +# +# An empty script is one trivial solution, and here is another: +# echo "42" > ch-1.pl && perl -p -e '' ch-1.pl + +import sys +from random import shuffle + +f = open(sys.argv[0], "r") +text = f.read() +words = text.split() +shuffle(words) +print(words[0]) diff --git a/challenge-286/paulo-custodio/python/ch-2.py b/challenge-286/paulo-custodio/python/ch-2.py new file mode 100644 index 0000000000..b31367eb72 --- /dev/null +++ b/challenge-286/paulo-custodio/python/ch-2.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 + +# Challenge 286 +# +# Task 2: Order Game +# Submitted by: Mohammad Sajid Anwar +# +# You are given an array of integers, @ints, whose length is a power of 2. +# +# Write a script to play the order game (min and max) and return the last element. +# Example 1 +# +# Input: @ints = (2, 1, 4, 5, 6, 3, 0, 2) +# Output: 1 +# +# Operation 1: +# +# min(2, 1) = 1 +# max(4, 5) = 5 +# min(6, 3) = 3 +# max(0, 2) = 2 +# +# Operation 2: +# +# min(1, 5) = 1 +# max(3, 2) = 3 +# +# Operation 3: +# +# min(1, 3) = 1 +# +# Example 2 +# +# Input: @ints = (0, 5, 3, 2) +# Output: 0 +# +# Operation 1: +# +# min(0, 5) = 0 +# max(3, 2) = 3 +# +# Operation 2: +# +# min(0, 3) = 0 +# +# Example 3 +# +# Input: @ints = (9, 2, 1, 4, 5, 6, 0, 7, 3, 1, 3, 5, 7, 9, 0, 8) +# Output: 2 +# +# Operation 1: +# +# min(9, 2) = 2 +# max(1, 4) = 4 +# min(5, 6) = 5 +# max(0, 7) = 7 +# min(3, 1) = 1 +# max(3, 5) = 5 +# min(7, 9) = 7 +# max(0, 8) = 8 +# +# Operation 2: +# +# min(2, 4) = 2 +# max(5, 7) = 7 +# min(1, 5) = 1 +# max(7, 8) = 8 +# +# Operation 3: +# +# min(2, 7) = 2 +# max(1, 8) = 8 +# +# Operation 4: +# +# min(2, 8) = 2 + +import sys + +def reduce(nums): + out = [] + while len(nums) > 0: + if len(nums) >= 2: + out.append(min(nums[0], nums[1])) + if len(nums) >= 4: + out.append(max(nums[2], nums[3])) + nums = nums[4:] + return out + +nums = list(map(int, sys.argv[1:])) +while len(nums) > 1: + nums = reduce(nums) + +print(nums[0]) -- cgit From 4cec80ad6cca76ed64aa9b76f1a0ff47e6f684db Mon Sep 17 00:00:00 2001 From: Paulo Custodio Date: Tue, 17 Sep 2024 11:10:54 +0100 Subject: Add tests to Challenge 286 --- challenge-286/paulo-custodio/perl/ch-1.pl | 8 +++++++- challenge-286/paulo-custodio/python/ch-1.py | 12 ++++++++++-- challenge-286/paulo-custodio/t/test-1.yaml | 5 +++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 challenge-286/paulo-custodio/t/test-1.yaml diff --git a/challenge-286/paulo-custodio/perl/ch-1.pl b/challenge-286/paulo-custodio/perl/ch-1.pl index 078cf5ee01..d6872f72f5 100644 --- a/challenge-286/paulo-custodio/perl/ch-1.pl +++ b/challenge-286/paulo-custodio/perl/ch-1.pl @@ -30,4 +30,10 @@ use Modern::Perl; use Path::Tiny; use List::Util 'shuffle'; -say((shuffle(split " ", path($0)->slurp))[0]); +if (@ARGV) { + my $n = shift // 0; + say((split " ", path($0)->slurp)[$n]); +} +else { + say((shuffle(split " ", path($0)->slurp))[0]); +} diff --git a/challenge-286/paulo-custodio/python/ch-1.py b/challenge-286/paulo-custodio/python/ch-1.py index 28e9703901..af7f2835a7 100644 --- a/challenge-286/paulo-custodio/python/ch-1.py +++ b/challenge-286/paulo-custodio/python/ch-1.py @@ -29,8 +29,16 @@ import sys from random import shuffle +n = -1 +if len(sys.argv) == 2: + n = int(sys.argv[1]) + f = open(sys.argv[0], "r") text = f.read() words = text.split() -shuffle(words) -print(words[0]) + +if n == -1: + shuffle(words) + print(words[0]) +else: + print(words[n]) diff --git a/challenge-286/paulo-custodio/t/test-1.yaml b/challenge-286/paulo-custodio/t/test-1.yaml new file mode 100644 index 0000000000..807491dac2 --- /dev/null +++ b/challenge-286/paulo-custodio/t/test-1.yaml @@ -0,0 +1,5 @@ +- setup: + cleanup: + args: 3 + input: + output: Challenge -- cgit From ff087e34ad3f29c637acbfc6a0026e60daa242e6 Mon Sep 17 00:00:00 2001 From: Paulo Custodio Date: Tue, 17 Sep 2024 14:58:18 +0100 Subject: Fix implementation of challenge 287, task 1 --- challenge-287/paulo-custodio/perl/ch-1.pl | 42 +++++++++---- challenge-287/paulo-custodio/python/ch-1.py | 98 +++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 13 deletions(-) create mode 100644 challenge-287/paulo-custodio/python/ch-1.py diff --git a/challenge-287/paulo-custodio/perl/ch-1.pl b/challenge-287/paulo-custodio/perl/ch-1.pl index 792483bb33..7493dc8fc0 100644 --- a/challenge-287/paulo-custodio/perl/ch-1.pl +++ b/challenge-287/paulo-custodio/perl/ch-1.pl @@ -53,24 +53,18 @@ use Modern::Perl; say steps_to_strong(shift // ""); sub steps_to_strong { - my($pass) = @_; - - my %avail_chars; - $avail_chars{$_} = 1 for ('0'..'9', 'A'..'Z', 'a'..'z'); - delete $avail_chars{$_} for (split //, $pass); + my($password) = @_; my $steps = 0; - while (!is_strong($pass)) { - if ($pass =~ /(.)\1\1+/) { + while (!is_strong($password)) { + my $new_ch = next_char($password); + + if ($password =~ /(.)\1\1+/) { my $ch = $1; - my $new_ch = (keys %avail_chars)[0]; - $pass =~ s/$ch{3}/$ch$ch$new_ch$ch/; - delete $avail_chars{$new_ch}; + $password =~ s/$ch{3}/$ch$ch$new_ch$ch/; } else { - my $new_ch = (keys %avail_chars)[0]; - $pass .= $new_ch; - delete $avail_chars{$new_ch}; + $password .= $new_ch; } $steps++; } @@ -81,3 +75,25 @@ sub is_strong { local($_) = @_; return length($_)>=6 && /[a-z]/ && /[A-Z]/ && /[0-9]/ && !/(.)\1\1+/; } + +sub next_char { + my($password) = @_; + + my $avail_chars = ""; + if ($password !~ /[0-9]/) { + $avail_chars .= join "", '0'..'9'; + } + if ($password !~ /[A-Z]/) { + $avail_chars .= join "", 'A'..'Z'; + } + if ($password !~ /[a-z]/) { + $avail_chars .= join "", 'a'..'z'; + } + $avail_chars .= join "", '0'..'9', 'A'..'Z', 'a'..'z'; + + for my $ch (split //, $password) { + $avail_chars =~ s/$ch//g; + } + + return substr($avail_chars, 0, 1); +} diff --git a/challenge-287/paulo-custodio/python/ch-1.py b/challenge-287/paulo-custodio/python/ch-1.py new file mode 100644 index 0000000000..2075f31565 --- /dev/null +++ b/challenge-287/paulo-custodio/python/ch-1.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 + +# Challenge 287 +# +# Task 1: Strong Password +# Submitted by: Mohammad Sajid Anwar +# +# You are given a string, $str. +# +# Write a program to return the minimum number of steps required to make the +# given string very strong password. If it is already strong then return 0. +# +# Criteria: +# +# - It must have at least 6 characters. +# - It must contains at least one lowercase letter, at least one upper case +# letter and at least one digit. +# - It shouldn't contain 3 repeating characters in a row. +# +# Following can be considered as one step: +# +# - Insert one character +# - Delete one character +# - Replace one character with another +# +# Example 1 +# +# Input: $str = "a" +# Output: 5 +# +# Example 2 +# +# Input: $str = "aB2" +# Output: 3 +# +# Example 3 +# +# Input: $str = "PaaSW0rd" +# Output: 0 +# +# Example 4 +# +# Input: $str = "Paaasw0rd" +# Output: 1 +# +# Example 5 +# +# Input: $str = "aaaaa" +# Output: 2 + +import re +import sys + +def is_strong(password): + if len(password) < 6: + return False + elif not re.search(r'[a-z]', password): + return False + elif not re.search(r'[A-Z]', password): + return False + elif not re.search(r'[0-9]', password): + return False + elif re.search(r'(.)\1\1+', password): + return False + else: + return True + +def charset(a, b): + return "".join([chr(x) for x in range(ord(a), ord(b)+1)]) + +def next_char(password): + avail_chars = "" + if not re.search(r'[a-z]', password): + avail_chars += charset('a', 'z') + if not re.search(r'[A-Z]', password): + avail_chars += charset('A', 'Z') + if not re.search(r'[0-9]', password): + avail_chars += charset('0', '9') + avail_chars += charset('a', 'z') + avail_chars += charset('A', 'Z') + avail_chars += charset('0', '9') + + for ch in password: + avail_chars, _ = re.subn(ch, '', avail_chars) + + return avail_chars[0] + +def steps_to_strong(password): + steps = 0 + while not is_strong(password): + if re.search(r'(.)\1\1+', password): + password = re.sub(r'(.)\1\1', r'\1\1'+next_char(password)+'\1', password) + else: + password += next_char(password) + steps += 1 + return steps + +print(steps_to_strong(sys.argv[1])) -- cgit From 683648e5b3d9efcb915ce74017651d524978d510 Mon Sep 17 00:00:00 2001 From: Paulo Custodio Date: Tue, 17 Sep 2024 15:15:21 +0100 Subject: Add Python solution to challenge 287 --- challenge-287/paulo-custodio/python/ch-2.py | 77 +++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 challenge-287/paulo-custodio/python/ch-2.py diff --git a/challenge-287/paulo-custodio/python/ch-2.py b/challenge-287/paulo-custodio/python/ch-2.py new file mode 100644 index 0000000000..9e3a00ea6a --- /dev/null +++ b/challenge-287/paulo-custodio/python/ch-2.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 + +# Challenge 287 +# +# Task 2: Valid Number +# Submitted by: Mohammad Sajid Anwar +# +# You are given a string, $str. +# +# Write a script to find if it is a valid number. +# +# Conditions for a valid number: +# +# - An integer number followed by an optional exponent. +# - A decimal number followed by an optional exponent. +# - An integer number is defined with an optional sign '-' or '+' followed by digits. +# +# Decimal Number: +# +# A decimal number is defined with an optional sign '-' or '+' followed by one +# of the following definitions: +# - Digits followed by a dot '.'. +# - Digits followed by a dot '.' followed by digits. +# - A dot '.' followed by digits. +# +# Exponent: +# +# An exponent is defined with an exponent notation 'e' or 'E' followed by an integer number. +# +# Example 1 +# +# Input: $str = "1" +# Output: true +# +# Example 2 +# +# Input: $str = "a" +# Output: false +# +# Example 3 +# +# Input: $str = "." +# Output: false +# +# Example 4 +# +# Input: $str = "1.2e4.2" +# Output: false +# +# Example 5 +# +# Input: $str = "-1." +# Output: true +# +# Example 6 +# +# Input: $str = "+1E-8" +# Output: true +# +# Example 7 +# +# Input: $str = ".44" +# Output: true + +import re +import sys + +if re.search(r' ^ [-+]? '+ + r' (?: \d+ \. \d* | '+ + r' \d* \. \d+ | '+ + r' \d+ '+ + r' ) '+ + r' (?: e [-+]? \d+ )? '+ + r' $', sys.argv[1], re.X+re.I): + print('true') +else: + print('false') -- cgit From c6a94bb22a6fa421be34db82d237a197dd9f2808 Mon Sep 17 00:00:00 2001 From: Paulo Custodio Date: Tue, 17 Sep 2024 16:12:02 +0100 Subject: Add Python solution to challenge 060 --- challenge-060/paulo-custodio/perl/ch-1.pl | 4 +-- challenge-060/paulo-custodio/perl/ch-2.pl | 2 +- challenge-060/paulo-custodio/python/ch-1.py | 43 +++++++++++++++++++++++++ challenge-060/paulo-custodio/python/ch-2.py | 50 +++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 challenge-060/paulo-custodio/python/ch-1.py create mode 100644 challenge-060/paulo-custodio/python/ch-2.py diff --git a/challenge-060/paulo-custodio/perl/ch-1.pl b/challenge-060/paulo-custodio/perl/ch-1.pl index 6aac747b1a..aa47f1375b 100644 --- a/challenge-060/paulo-custodio/perl/ch-1.pl +++ b/challenge-060/paulo-custodio/perl/ch-1.pl @@ -2,13 +2,13 @@ # Challenge 060 # -# TASK #1 › Excel Column +# TASK #1 > Excel Column # Reviewed by: Ryan Thompson # Write a script that accepts a number and returns the Excel Column Name it # represents and vice-versa. # # Excel columns start at A and increase lexicographically using the 26 letters -# of the English alphabet, A..Z. After Z, the columns pick up an extra “digit”, +# of the English alphabet, A..Z. After Z, the columns pick up an extra "digit", # going from AA, AB, etc., which could (in theory) continue to an arbitrary # number of digits. In practice, Excel sheets are limited to 16,384 columns. # diff --git a/challenge-060/paulo-custodio/perl/ch-2.pl b/challenge-060/paulo-custodio/perl/ch-2.pl index 6ec49647e7..ba89e73e05 100644 --- a/challenge-060/paulo-custodio/perl/ch-2.pl +++ b/challenge-060/paulo-custodio/perl/ch-2.pl @@ -2,7 +2,7 @@ # Challenge 060 # -# TASK #2 › Find Numbers +# TASK #2 > Find Numbers # Reviewed by: Ryan Thompson # Write a script that accepts list of positive numbers (@L) and two positive # numbers $X and $Y. diff --git a/challenge-060/paulo-custodio/python/ch-1.py b/challenge-060/paulo-custodio/python/ch-1.py new file mode 100644 index 0000000000..10efd3a1fc --- /dev/null +++ b/challenge-060/paulo-custodio/python/ch-1.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +# Challenge 060 +# +# TASK #1 > Excel Column +# Reviewed by: Ryan Thompson +# Write a script that accepts a number and returns the Excel Column Name it +# represents and vice-versa. +# +# Excel columns start at A and increase lexicographically using the 26 letters +# of the English alphabet, A..Z. After Z, the columns pick up an extra "digit", +# going from AA, AB, etc., which could (in theory) continue to an arbitrary +# number of digits. In practice, Excel sheets are limited to 16,384 columns. +# +# Example +# Input Number: 28 +# Output: AB +# +# Input Column Name: AD +# Output: 30 + +import re +import sys + +def col2num(col): + num = 0 + for digit in col: + num = 26*num + ord(digit)-ord('A') + 1 + return num + +def num2col(num): + col = "" + while num > 0: + digit = (num-1) % 26 + num = int((num-1) / 26) + col = chr(ord('A')+digit) + col + return col + +arg = sys.argv[1] +if re.search(r'^\d+$', arg): + print(num2col(int(arg))) +else: + print(col2num(arg)) diff --git a/challenge-060/paulo-custodio/python/ch-2.py b/challenge-060/paulo-custodio/python/ch-2.py new file mode 100644 index 0000000000..5a159ce266 --- /dev/null +++ b/challenge-060/paulo-custodio/python/ch-2.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 + +# Challenge 060 +# +# TASK #2 > Find Numbers +# Reviewed by: Ryan Thompson +# Write a script that accepts list of positive numbers (@L) and two positive +# numbers $X and $Y. +# +# The script should print all possible numbers made by concatenating the numbers +# from @L, whose length is exactly $X but value is less than $Y. +# +# Example +# Input: +# +# @L = (0, 1, 2, 5); +# $X = 2; +# $Y = 21; +# Output: +# +# 10, 11, 12, 15, 20 + +import sys + +def combine1(combin, prefix, n, digits): + if len(prefix) == n: + num = int(prefix) + if not num in combin: + combin.add(num) + else: + for digit in digits: + combine1(combin, prefix+digit, n, digits) + +def combine(digits): + combin = set() + for n in range(1, len(digits)+1): + combine1(combin, "", n, digits) + nums = sorted(list(combin)) + return nums + +def numbers(X, Y, L): + nums = combine(L) + nums = list(filter(lambda x:len(str(x))==X and x Date: Tue, 17 Sep 2024 16:35:26 +0100 Subject: Add Python solution to challenge 061 --- challenge-061/paulo-custodio/perl/ch-1.pl | 2 +- challenge-061/paulo-custodio/perl/ch-2.pl | 4 +-- challenge-061/paulo-custodio/python/ch-1.py | 36 ++++++++++++++++++++++ challenge-061/paulo-custodio/python/ch-2.py | 46 +++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 challenge-061/paulo-custodio/python/ch-1.py create mode 100644 challenge-061/paulo-custodio/python/ch-2.py diff --git a/challenge-061/paulo-custodio/perl/ch-1.pl b/challenge-061/paulo-custodio/perl/ch-1.pl index a8a9e2faaf..fcfcd54dd7 100644 --- a/challenge-061/paulo-custodio/perl/ch-1.pl +++ b/challenge-061/paulo-custodio/perl/ch-1.pl @@ -2,7 +2,7 @@ # Challenge 061 # -# TASK #1 › Product SubArray +# TASK #1 > Product SubArray # Reviewed by: Ryan Thompson # Given a list of 4 or more numbers, write a script to find the contiguous # sublist that has the maximum product. The length of the sublist is irrelevant; diff --git a/challenge-061/paulo-custodio/perl/ch-2.pl b/challenge-061/paulo-custodio/perl/ch-2.pl index f7a8e53653..5a2801f33b 100644 --- a/challenge-061/paulo-custodio/perl/ch-2.pl +++ b/challenge-061/paulo-custodio/perl/ch-2.pl @@ -2,7 +2,7 @@ # Challenge 061 # -# TASK #2 › IPv4 Partition +# TASK #2 > IPv4 Partition # Reviewed by: Ryan Thompson # You are given a string containing only digits (0..9). The string should have # between 4 and 12 digits. @@ -11,7 +11,7 @@ # partitioning the input string. # # For the purpose of this challenge, a valid IPv4 address consists of four -# “octets” i.e. A, B, C and D, separated by dots (.). +# "octets" i.e. A, B, C and D, separated by dots (.). # # Each octet must be between 0 and 255, and must not have any leading zeroes. # (e.g., 0 is OK, but 01 is not.) diff --git a/challenge-061/paulo-custodio/python/ch-1.py b/challenge-061/paulo-custodio/python/ch-1.py new file mode 100644 index 0000000000..47e232e6aa --- /dev/null +++ b/challenge-061/paulo-custodio/python/ch-1.py @@ -0,0 +1,36 @@ +#!/usr/bin/env perl + +# Challenge 061 +# +# TASK #1 > Product SubArray +# Reviewed by: Ryan Thompson +# Given a list of 4 or more numbers, write a script to find the contiguous +# sublist that has the maximum product. The length of the sublist is irrelevant; +# your job is to maximize the product. +# +# Example +# Input: [ 2, 5, -1, 3 ] +# +# Output: [ 2, 5 ] which gives maximum product 10. + +import sys + +def product(nums): + prod = 1 + for x in nums: + prod *= x + return x + + +n = list(map(int, sys.argv[1:])) +max_sublist = [] +max_prod = int(-1e6) + +for i in range(0, len(n)): + for j in range(i, len(n)): + sublist = n[i:j+1] + prod = product(sublist) + if prod > max_prod: + max_sublist, max_prod = sublist, prod + +print(", ".join(list(map(str, max_sublist)))) diff --git a/challenge-061/paulo-custodio/python/ch-2.py b/challenge-061/paulo-custodio/python/ch-2.py new file mode 100644 index 0000000000..0cbd7cd9c9 --- /dev/null +++ b/challenge-061/paulo-custodio/python/ch-2.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 + +# Challenge 061 +# +# TASK #2 > IPv4 Partition +# Reviewed by: Ryan Thompson +# You are given a string containing only digits (0..9). The string should have +# between 4 and 12 digits. +# +# Write a script to print every possible valid IPv4 address that can be made by +# partitioning the input string. +# +# For the purpose of this challenge, a valid IPv4 address consists of four +# "octets" i.e. A, B, C and D, separated by dots (.). +# +# Each octet must be between 0 and 255, and must not have any leading zeroes. +# (e.g., 0 is OK, but 01 is not.) +# +# Example +# Input: 25525511135, +# +# Output: +# +# 255.255.11.135 +# 255.255.111.35 + +import re +import sys + +def partition1(prefix, digits): + if re.search(r'^(\d+\.){4}$', prefix): + if digits == "": + prefix = prefix[:-1] + print(prefix) + else: + for l in range(1, 4): + if l <= len(digits): + part = digits[:l] + if int(part) <= 255: + partition1(prefix+part+".", digits[l:]) + +def partition(digits): + partition1("", digits) + +digits = sys.argv[1] +partition(digits) -- cgit From 6ddee0d9fd99125d82152509ca789840553d65c5 Mon Sep 17 00:00:00 2001 From: Paulo Custodio Date: Tue, 17 Sep 2024 21:37:33 +0100 Subject: Add Python solution to challenge 062 --- challenge-062/paulo-custodio/perl/ch-1.pl | 4 +- challenge-062/paulo-custodio/perl/ch-2.pl | 10 +-- challenge-062/paulo-custodio/python/ch-1.py | 71 +++++++++++++++++++ challenge-062/paulo-custodio/python/ch-2.py | 103 ++++++++++++++++++++++++++++ 4 files changed, 181 insertions(+), 7 deletions(-) create mode 100644 challenge-062/paulo-custodio/python/ch-1.py create mode 100644 challenge-062/paulo-custodio/python/ch-2.py diff --git a/challenge-062/paulo-custodio/perl/ch-1.pl b/challenge-062/paulo-custodio/perl/ch-1.pl index e6cb2d6ece..538125b0d3 100644 --- a/challenge-062/paulo-custodio/perl/ch-1.pl +++ b/challenge-062/paulo-custodio/perl/ch-1.pl @@ -2,7 +2,7 @@ # Challenge 062 # -# TASK #1 › Sort Email Addresses +# TASK #1 > Sort Email Addresses # Submitted by: Neil Bowers # Reviewed by: Ryan Thompson # @@ -11,7 +11,7 @@ # the left of the @ (known as the mailbox). # # Note that the domain is case-insensitive, while the mailbox part is case -# sensitive. (Some email providers choose to ignore case, but that’s another +# sensitive. (Some email providers choose to ignore case, but that's another # matter entirely.) # # If your script is invoked with arguments, it should treat them as file names diff --git a/challenge-062/paulo-custodio/perl/ch-2.pl b/challenge-062/paulo-custodio/perl/ch-2.pl index 2db5a3e870..2e2d9d2e35 100644 --- a/challenge-062/paulo-custodio/perl/ch-2.pl +++ b/challenge-062/paulo-custodio/perl/ch-2.pl @@ -2,10 +2,10 @@ # Challenge 062 # -# TASK #2 › N Queens +# TASK #2 > N Queens # Submitted by: Ryan Thompson # -# A standard 8×8 chessboard has 64 squares. The Queen is a chesspiece that can +# A standard 8x8 chessboard has 64 squares. The Queen is a chesspiece that can # attack in 8 directions, as shown by the green shaded squares below: # # @@ -15,15 +15,15 @@ # overlap). In fact, there are multiple ways to do so, and this is a favourite # undergraduate assignment in computer science. # -# But here at PWC, we’re going to take it into the next dimension! +# But here at PWC, we're going to take it into the next dimension! # # Your job is to write a script to work with a three dimensional chess cube, -# M×M×M in size, and find a solution that maximizes the number of queens that +# MxMxM in size, and find a solution that maximizes the number of queens that # can be placed in that cube without attacking each other. Output one possible # solution. # # Example -# A trivial 2×2×2 solution might look like this (1 = queen, 0 = empty): +# A trivial 2x2x2 solution might look like this (1 = queen, 0 = empty): # # [ # [[1,0], # Layer 1 diff --git a/challenge-062/paulo-custodio/python/ch-1.py b/challenge-062/paulo-custodio/python/ch-1.py new file mode 100644 index 0000000000..cc119d7a09 --- /dev/null +++ b/challenge-062/paulo-custodio/python/ch-1.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +# Challenge 062 +# +# TASK #1 > Sort Email Addresses +# Submitted by: Neil Bowers +# Reviewed by: Ryan Thompson +# +# Write a script that takes a list of email addresses (one per line) and sorts +# them first by the domain part of the email address, and then by the part to +# the left of the @ (known as the mailbox). +# +# Note that the domain is case-insensitive, while the mailbox part is case +# sensitive. (Some email providers choose to ignore case, but that's another +# matter entirely.) +# +# If your script is invoked with arguments, it should treat them as file names +# and read them in order, otherwise your script should read email addresses from +# standard input. +# +# Bonus +# Add a -u option which only includes unique email addresses in the output, just +# like sort -u. +# +# Example +# If given the following list: +# +# name@example.org +# rjt@cpan.org +# Name@example.org +# rjt@CPAN.org +# user@alpha.example.org +# Your script (without -u) would return: +# +# user@alpha.example.org +# rjt@cpan.org +# rjt@CPAN.org +# Name@example.org +# name@example.org +# With -u, the script would return: +# +# user@alpha.example.org +# rjt@CPAN.org +# Name@example.org +# name@example.org + +import sys +from getopt import getopt + +opt_u = False +opts, args = getopt(sys.argv[1:], 'u') +for o, a in opts: + if o == '-u': + opt_u = True + +mails = [line.strip() for line in sys.stdin] + +sorted_mails = sorted( + map(lambda x: [x] + x.split('@'), mails), + key=lambda x: (x[2].lower(), x[1]) +) + +if opt_u: + seen = set() + sorted_mails = [ + [f"{mail[0]}"] + for mail in sorted_mails + if (key := f"{mail[1]}@{mail[2].lower()}") not in seen and not seen.add(key) + ] + +print("\n".join([x[0] for x in sorted_mails])) diff --git a/challenge-062/paulo-custodio/python/ch-2.py b/challenge-062/paulo-custodio/python/ch-2.py new file mode 100644 index 0000000000..ca8a0f3c6a --- /dev/null +++ b/challenge-062/paulo-custodio/python/ch-2.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 + +# Challenge 062 +# +# TASK #2 > N Queens +# Submitted by: Ryan Thompson +# +# A standard 8x8 chessboard has 64 squares. The Queen is a chesspiece that can +# attack in 8 directions, as shown by the green shaded squares below: +# +# +# +# It is possible to place 8 queens on to a single chessboard such that none of +# the queens can attack each other (i.e., their shaded squares would not +# overlap). In fact, there are multiple ways to do so, and this is a favourite +# undergraduate assignment in computer science. +# +# But here at PWC, we're going to take it into the next dimension! +# +# Your job is to write a script to work with a three dimensional chess cube, +# MxMxM in size, and find a solution that maximizes the number of queens that +# can be placed in that cube without attacking each other. Output one possible +# solution. +# +# Example +# A trivial 2x2x2 solution might look like this (1 = queen, 0 = empty): +# +# [ +# [[1,0], # Layer 1 +# [0,0]], +# +# [[0,0], # Layer 2 +# [0,0]], +# ] + +from copy import deepcopy +import re + +M = 2 + +board = [[[0 for _ in range(M)] for _ in range(M)] for _ in range(M)] +max_board = deepcopy(board) +max_queens = 0 + +def set_position(board, l, r, c): + if 0 <= l < M and 0 <= r < M and 0 <= c < M: + board[l][r][c] = 1 + +def place_queens(queens, board): + global max_queens, max_board + + # check for empty spaces + full = True + for l in range(M): + for r in range(M): + for c in range(M): + if board[l][r][c] == 0: + full = False + # empty, place queen + copy_board = deepcopy(board) + # fill attack positions + for i in range(M): + set_position(copy_board, i, r, c) + set_position(copy_board, l, i, c) + set_position(copy_board, l, r, i) + + set_position(copy_board, l, r-i, c-i) + set_position(copy_board, l, r-i, c+i) + set_position(copy_board, l, r+i, c-i) + set_position(copy_board, l, r+i, c+i) + + set_position(copy_board, l-i, r, c-i) + set_position(copy_board, l-i, r, c+i) + set_position(copy_board, l+i, r, c-i) + set_position(copy_board, l+i, r, c+i) + + set_position(copy_board, l-i, r-i, c) + set_position(copy_board, l-i, r+i, c) + set_position(copy_board, l+i, r-i, c) + set_position(copy_board, l+i, r+i, c) + + set_position(copy_board, l-i, r-i, c-i) + set_position(copy_board, l-i, r-i, c+i) + set_position(copy_board, l-i, r+i, c-i) + set_position(copy_board, l-i, r+i, c+i) + + set_position(copy_board, l+i, r-i, c-i) + set_position(copy_board, l+i, r-i, c+i) + set_position(copy_board, l+i, r+i, c-i) + set_position(copy_board, l+i, r+i, c+i) + # fill queen position + copy_board[l][r][c] = 'Q' + # recurse + place_queens(queens + 1, copy_board) + if full: + if queens > max_queens: + max_queens = queens + max_board = deepcopy(board) + +place_queens(0, board) +out = str(max_board) +out, _ = re.subn("'", '"', out) +print(out) -- cgit From 74244e2aaf6d04398424e51a3df0aa05bb37bb48 Mon Sep 17 00:00:00 2001 From: Paulo Custodio Date: Tue, 17 Sep 2024 21:49:51 +0100 Subject: Add Python solution to challenge 063 --- challenge-063/paulo-custodio/Makefile | 1 + challenge-063/paulo-custodio/perl/ch-1.pl | 4 +-- challenge-063/paulo-custodio/perl/ch-2.pl | 5 +-- challenge-063/paulo-custodio/python/ch-1.py | 45 +++++++++++++++++++++++++++ challenge-063/paulo-custodio/python/ch-2.py | 47 +++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 challenge-063/paulo-custodio/python/ch-1.py create mode 100644 challenge-063/paulo-custodio/python/ch-2.py diff --git a/challenge-063/paulo-custodio/Makefile b/challenge-063/paulo-custodio/Makefile index 0d5753b0fb..3eba7cf291 100644 --- a/challenge-063/paulo-custodio/Makefile +++ b/challenge-063/paulo-custodio/Makefile @@ -1,3 +1,4 @@ all: perl perl/ch-1.pl + python3 python/ch-1.py perl ../../challenge-001/paulo-custodio/test.pl diff --git a/challenge-063/paulo-custodio/perl/ch-1.pl b/challenge-063/paulo-custodio/perl/ch-1.pl index d3900d26b7..bf8874c318 100644 --- a/challenge-063/paulo-custodio/perl/ch-1.pl +++ b/challenge-063/paulo-custodio/perl/ch-1.pl @@ -2,7 +2,7 @@ # Challenge 063 # -# TASK #1 › Last Word +# TASK #1 > Last Word # Submitted by: Mohammad S Anwar # Reviewed by: Ryan Thompson # @@ -10,7 +10,7 @@ # $regexp found in the given string, or undef if the string does not contain a # word matching $regexp. # -# For this challenge, a “word” is defined as any character sequence consisting +# For this challenge, a "word" is defined as any character sequence consisting # of non-whitespace characters (\S) only. That means punctuation and other # symbols are part of the word. # diff --git a/challenge-063/paulo-custodio/perl/ch-2.pl b/challenge-063/paulo-custodio/perl/ch-2.pl index 70ad2a5098..c477a46a40 100644 --- a/challenge-063/paulo-custodio/perl/ch-2.pl +++ b/challenge-063/paulo-custodio/perl/ch-2.pl @@ -2,11 +2,12 @@ # Challenge 063 # -# TASK #2 › Rotate String +# TASK #2 > Rotate String # Submitted by: Mohammad S Anwar # Reviewed by: Ryan Thompson # -# Given a word made up of an arbitrary number of x and y characters, that word can be rotated as follows: For the ith rotation (starting at i = 1), +# Given a word made up of an arbitrary number of x and y characters, that word +# can be rotated as follows: For the ith rotation (starting at i = 1), # i % length(word) characters are moved from the front of the string to the end. # Thus, for the string xyxx, the initial (i = 1) % 4 = 1 character (x) is moved # to the end, forming yxxx. On the second rotation, (i = 2) % 4 = 2 characters diff --git a/challenge-063/paulo-custodio/python/ch-1.py b/challenge-063/paulo-custodio/python/ch-1.py new file mode 100644 index 0000000000..5fb968ca0d --- /dev/null +++ b/challenge-063/paulo-custodio/python/ch-1.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 + +# Challenge 063 +# +# TASK #1 > Last Word +# Submitted by: Mohammad S Anwar +# Reviewed by: Ryan Thompson +# +# Define sub last_word($string, $regexp) that returns the last word matching +# $regexp found in the given string, or undef if the string does not contain a +# word matching $regexp. +# +# For this challenge, a "word" is defined as any character sequence consisting +# of non-whitespace characters (\S) only. That means punctuation and other +# symbols are part of the word. +# +# The $regexp is a regular expression. Take care that the regexp can only match +# individual words! See the Examples for one way this can break if you are not +# careful. +# +# Examples +# last_word(' hello world', qr/[ea]l/); # 'hello' +# last_word("Don't match too much, Chet!", qr/ch.t/i); # 'Chet!' +# last_word("spaces in regexp won't match", qr/in re/); # undef +# last_word( join(' ', 1..1e6), qr/^(3.*?){3}/); # '399933' + +import re +import unittest + +def last_word(text, pattern): + words = text.split(' ') + for word in reversed(words): + if re.search(pattern, word, re.IGNORECASE): + return word + return None + +class TestLastWord(unittest.TestCase): + def test_last_word(self): + self.assertEqual(last_word(' hello world', r'[ea]l'), 'hello') + self.assertEqual(last_word("Don't match too much, Chet!", r'ch.t'), 'Chet!') + self.assertIsNone(last_word("spaces in regexp won't match", r'in re')) + self.assertEqual(last_word(' '.join(str(i) for i in range(1, int(1e6) + 1)), r'^(3.*?){3}'), '399933') + +if __name__ == '__main__': + unittest.main() diff --git a/challenge-063/paulo-custodio/python/ch-2.py b/challenge-063/paulo-custodio/python/ch-2.py new file mode 100644 index 0000000000..37f0bab8d2 --- /dev/null +++ b/challenge-063/paulo-custodio/python/ch-2.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +# Challenge 063 +# +# TASK #2 > Rotate String +# Submitted by: Mohammad S Anwar +# Reviewed by: Ryan Thompson +# +# Given a word made up of an arbitrary number of x and y characters, that word +# can be rotated as follows: For the ith rotation (starting at i = 1), +# i % length(word) characters are moved from the front of the string to the end. +# Thus, for the string xyxx, the initial (i = 1) % 4 = 1 character (x) is moved +# to the end, forming yxxx. On the second rotation, (i = 2) % 4 = 2 characters +# (yx) are moved to the end, forming xxyx, and so on. See below for a complete +# example. +# +# Your task is to write a function that takes a string of xs and ys and returns +# the minimum non-zero number of rotations required to obtain the original +# string. You may show the individual rotations if you wish, but that is not +# required. +# +# Example +# Input: $word = 'xyxx'; +# +# Rotation 1: you get yxxx by moving x to the end. +# Rotation 2: you get xxyx by moving yx to the end. +# Rotation 3: you get xxxy by moving xxy to the end. +# Rotation 4: you get xxxy by moving nothing as 4 % length(xyxx) == 0. +# Rotation 5: you get xxyx by moving x to the end. +# Rotation 6: you get yxxx by moving xx to the end. +# Rotation 7: you get xyxx by moving yxx to the end which is same as the given word. +# Output: 7 + +import sys + +def count_rotations(in_str=""): + count = 0 + str_val = in_str + while True: + count += 1 + move = count % len(str_val) + str_val = str_val[move:] + str_val[:move] + if in_str == str_val: + break + return count + +print(count_rotations(sys.argv[1] if len(sys.argv) > 1 else "")) -- cgit From 51c035e04c5ae5f9f02555206f57eb675a737617 Mon Sep 17 00:00:00 2001 From: Paulo Custodio Date: Tue, 17 Sep 2024 22:07:51 +0100 Subject: Add Python solution to challenge 064 --- challenge-064/paulo-custodio/Makefile | 2 + challenge-064/paulo-custodio/perl/ch-1.pl | 4 +- challenge-064/paulo-custodio/perl/ch-2.pl | 6 +-- challenge-064/paulo-custodio/python/ch-1.py | 60 +++++++++++++++++++++++++++++ challenge-064/paulo-custodio/python/ch-2.py | 52 +++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 challenge-064/paulo-custodio/python/ch-1.py create mode 100644 challenge-064/paulo-custodio/python/ch-2.py diff --git a/challenge-064/paulo-custodio/Makefile b/challenge-064/paulo-custodio/Makefile index ba9a2bf399..9c7316cd76 100644 --- a/challenge-064/paulo-custodio/Makefile +++ b/challenge-064/paulo-custodio/Makefile @@ -1,3 +1,5 @@ all: perl perl/ch-1.pl perl perl/ch-2.pl + python3 python/ch-1.py + python3 python/ch-2.py diff --git a/challenge-064/paulo-custodio/perl/ch-1.pl b/challenge-064/paulo-custodio/perl/ch-1.pl index 5a1197d4a3..e5acc1ebf1 100644 --- a/challenge-064/paulo-custodio/perl/ch-1.pl +++ b/challenge-064/paulo-custodio/perl/ch-1.pl @@ -2,11 +2,11 @@ # Challenge 064 # -# TASK #1 › Minimum Sum Path +# TASK #1 > Minimum Sum Path # Submitted by: Mohammad S Anwar # Reviewed by: Ryan Thompson # -# Given an m × n matrix with non-negative integers, write a script to find a +# Given an m x n matrix with non-negative integers, write a script to find a # path from top left to bottom right which minimizes the sum of all numbers # along its path. You can only move either down or right at any point in time. # diff --git a/challenge-064/paulo-custodio/perl/ch-2.pl b/challenge-064/paulo-custodio/perl/ch-2.pl index e4a4532f3e..5ae8da6e1e 100644 --- a/challenge-064/paulo-custodio/perl/ch-2.pl +++ b/challenge-064/paulo-custodio/perl/ch-2.pl @@ -2,7 +2,7 @@ # Challenge 064 # -# TASK #2 › Word Break +# TASK #2 > Word Break # Submitted by: Mohammad S Anwar # # You are given a string $S and an array of words @W. @@ -32,7 +32,7 @@ # 0 as none matching word found. use Modern::Perl; -use Math::Combinatorics 'combine'; +use Math::Combinatorics 'permute'; use Test::More; is word_break("perlweeklychallenge", "weekly", "challenge", "perl"), @@ -45,7 +45,7 @@ done_testing; sub word_break { my($S, @W) = @_; my $k = scalar(@W); - for (combine($k, @W)) { + for (permute(@W)) { my @words = @$_; if (join('', @words) eq $S) { return "@W"; diff --git a/challenge-064/paulo-custodio/python/ch-1.py b/challenge-064/paulo-custodio/python/ch-1.py new file mode 100644 index 0000000000..54982caa27 --- /dev/null +++ b/challenge-064/paulo-custodio/python/ch-1.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +# Challenge 064 +# +# TASK #1 > Minimum Sum Path +# Submitted by: Mohammad S Anwar +# Reviewed by: Ryan Thompson +# +# Given an m x n matrix with non-negative integers, write a script to find a +# path from top left to bottom right which minimizes the sum of all numbers +# along its path. You can only move either down or right at any point in time. +# +# Example +# Input: +# +# [ 1 2 3 ] +# [ 4 5 6 ] +# [ 7 8 9 ] +# The minimum sum path looks like this: +# +# 1?2?3 +# ? +# 6 +# ? +# 9 +# Thus, your script could output: 21 ( 1 ? 2 ? 3 ? 6 ? 9 ) + +import unittest +import sys + +def min_sum(m): + min_sum = [sys.maxsize] # Using a list to simulate a global variable + + def min_sum1(sum, r, c, m): + rows = len(m) + cols = len(m[0]) + sum += m[r][c] + if r == rows - 1 and c == cols - 1: # reached end + if sum < min_sum[0]: + min_sum[0] = sum + else: + if r + 1 < rows: + min_sum1(sum, r + 1, c, m) + if c + 1 < cols: + min_sum1(sum, r, c + 1, m) + + min_sum1(0, 0, 0, m) + return min_sum[0] + +class TestMinSum(unittest.TestCase): + def test_min_sum(self): + m = [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9] + ] + self.assertEqual(min_sum(m), 21) + +if __name__ == '__main__': + unittest.main() diff --git a/challenge-064/paulo-custodio/python/ch-2.py b/challenge-064/paulo-custodio/python/ch-2.py new file mode 100644 index 0000000000..12034bea57 --- /dev/null +++ b/challenge-064/paulo-custodio/python/ch-2.py @@ -0,0 +1,52 @@ +#!/usr/bin/env perl + +# Challenge 064 +# +# TASK #2 > Word Break +# Submitted by: Mohammad S Anwar +# +# You are given a string $S and an array of words @W. +# +# Write a script to find out if $S can be split into sequence of one or more +# words as in the given @W. +# +# Print the all the words if found otherwise print 0. +# +# Example 1: +# Input: +# +# $S = "perlweeklychallenge" +# @W = ("weekly", "challenge", "perl") +# +# Output: +# +# "perl", "weekly", "challenge" +# Example 2: +# Input: +# +# $S = "perlandraku" +# @W = ("python", "ruby", "haskell") +# +# Output: +# +# 0 as none matching word found. + +import itertools +import unittest + +def word_break(S, *W): + k = len(W) + for words in itertools.permutations(W): + if ''.join(words) == S: + return ' '.join(W) + return "0" + +class TestWordBreak(unittest.TestCase): + def test_word_break(self): + self.assertEqual(word_break("perlweeklychallenge", "weekly", "challenge", "perl"), + "weekly challenge perl") + self.assertEqual(word_break("perlandraku", "python", "ruby", "haskell"), + "0") + +if __name__ == '__main__': + unittest.main() -- cgit