diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2023-03-26 12:28:38 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-26 12:28:38 +0100 |
| commit | 2860bdf1fac3d5235cd68ede860853e15d69708e (patch) | |
| tree | a851f3361a3ed808425b940f8623e07465d3f276 | |
| parent | 0268632e64340f543178e3438a8ce741c3b775d4 (diff) | |
| parent | 2a6bb0ae68aad6f29c807dc4f0423768cc845d9a (diff) | |
| download | perlweeklychallenge-club-2860bdf1fac3d5235cd68ede860853e15d69708e.tar.gz perlweeklychallenge-club-2860bdf1fac3d5235cd68ede860853e15d69708e.tar.bz2 perlweeklychallenge-club-2860bdf1fac3d5235cd68ede860853e15d69708e.zip | |
Merge pull request #7796 from LubosKolouch/master
Challenges 035 038 042 LK Perl Python
| -rw-r--r-- | challenge-035/lubos-kolouch/perl/ch-1.pl | 57 | ||||
| -rw-r--r-- | challenge-035/lubos-kolouch/perl/ch-2.pl | 70 | ||||
| -rw-r--r-- | challenge-035/lubos-kolouch/python/ch-1.py | 62 | ||||
| -rw-r--r-- | challenge-035/lubos-kolouch/python/ch-2.py | 60 | ||||
| -rw-r--r-- | challenge-038/lubos-kolouch/perl/ch-1.pl | 39 | ||||
| -rw-r--r-- | challenge-038/lubos-kolouch/perl/ch-2.pl | 120 | ||||
| -rw-r--r-- | challenge-038/lubos-kolouch/python/ch-1.py | 30 | ||||
| -rw-r--r-- | challenge-038/lubos-kolouch/python/ch-2.py | 95 | ||||
| -rw-r--r-- | challenge-042/lubos-kolouch/perl/ch-1.pl | 19 | ||||
| -rw-r--r-- | challenge-042/lubos-kolouch/perl/ch-2.pl | 47 | ||||
| -rw-r--r-- | challenge-042/lubos-kolouch/python/ch-1.py | 35 | ||||
| -rw-r--r-- | challenge-042/lubos-kolouch/python/ch-2.py | 66 |
12 files changed, 700 insertions, 0 deletions
diff --git a/challenge-035/lubos-kolouch/perl/ch-1.pl b/challenge-035/lubos-kolouch/perl/ch-1.pl new file mode 100644 index 0000000000..186fc24c4d --- /dev/null +++ b/challenge-035/lubos-kolouch/perl/ch-1.pl @@ -0,0 +1,57 @@ +use strict; +use warnings; +use Test::More; + +# Define Morse code mappings +my %morse_code = ( + 'A' => '.-', + 'B' => '-...', + 'C' => '-.-.', + 'D' => '-..', + 'E' => '.', + 'F' => '..-.', + 'G' => '--.', + 'H' => '....', + 'I' => '..', + 'J' => '.---', + 'K' => '-.-', + 'L' => '.-..', + 'M' => '--', + 'N' => '-.', + 'O' => '---', + 'P' => '.--.', + 'Q' => '--.-', + 'R' => '.-.', + 'S' => '...', + 'T' => '-', + 'U' => '..-', + 'V' => '...-', + 'W' => '.--', + 'X' => '-..-', + 'Y' => '-.--', + 'Z' => '--..', + ' ' => '/' +); + +# Encode text into binary encoded Morse code +sub encode_morse { + my $text = shift; + my $encoded = ''; + foreach my $char ( split //, uc $text ) { + if ( exists $morse_code{$char} ) { + my $morse = $morse_code{$char}; + my @bits = (); + foreach my $symbol ( split //, $morse ) { + if ( $symbol eq '.' ) { + push @bits, '1', '0'; + } + elsif ( $symbol eq '-' ) { + push @bits, '1' x 3, '0'; + } + } + $encoded .= join( '0', @bits ) . '0'; + } + } + $encoded =~ s/0$//; # Remove trailing intra-character gap + return $encoded; +} diff --git a/challenge-035/lubos-kolouch/perl/ch-2.pl b/challenge-035/lubos-kolouch/perl/ch-2.pl new file mode 100644 index 0000000000..16fc9af817 --- /dev/null +++ b/challenge-035/lubos-kolouch/perl/ch-2.pl @@ -0,0 +1,70 @@ +use strict; +use warnings; +use Test::More; + +# Define Morse code mappings +my %morse_code = ( + '.-' => 'A', + '-...' => 'B', + '-.-.' => 'C', + '-..' => 'D', + '.' => 'E', + '..-.' => 'F', + '--.' => 'G', + '....' => 'H', + '..' => 'I', + '.---' => 'J', + '-.-' => 'K', + '.-..' => 'L', + '--' => 'M', + '-.' => 'N', + '---' => 'O', + '.--.' => 'P', + '--.-' => 'Q', + '.-.' => 'R', + '...' => 'S', + '-' => 'T', + '..-' => 'U', + '...-' => 'V', + '.--' => 'W', + '-..-' => 'X', + '-.--' => 'Y', + '--..' => 'Z', + '/' => ' ' +); + +# Decode binary encoded Morse code +sub decode_morse { + my $encoded = shift; + + # Split encoded text into words and characters + my @words = ( $encoded =~ /0{7}/g ); + my @letters = map { [ ( $_ =~ /0{3}/g ) ] } @words; + + # Convert Morse code to plaintext + my $plaintext = ''; + for my $word (@letters) { + for my $letter (@$word) { + if ( exists $morse_code{$letter} ) { + $plaintext .= $morse_code{$letter}; + } + else { + # If the Morse code is badly formed, try to recover by looking one digit ahead + for my $i ( 1 .. 3 ) { + my $lookahead = substr( $letter, $i ); + if ( exists $morse_code{$lookahead} ) { + $plaintext .= $morse_code{$lookahead}; + last; + } + } + +# If no valid Morse code sequence can be recovered, treat the character as a space + $plaintext .= ' ' + unless length $plaintext && substr( $plaintext, -1 ) eq ' '; + } + } + $plaintext .= ' '; + } + $plaintext =~ s/\s+$//; # Remove trailing space + return $plaintext; +} diff --git a/challenge-035/lubos-kolouch/python/ch-1.py b/challenge-035/lubos-kolouch/python/ch-1.py new file mode 100644 index 0000000000..a9d929615a --- /dev/null +++ b/challenge-035/lubos-kolouch/python/ch-1.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import unittest + +# Define Morse code mappings +morse_code = { + "A": ".-", + "B": "-...", + "C": "-.-.", + "D": "-..", + "E": ".", + "F": "..-.", + "G": "--.", + "H": "....", + "I": "..", + "J": ".---", + "K": "-.-", + "L": ".-..", + "M": "--", + "N": "-.", + "O": "---", + "P": ".--.", + "Q": "--.-", + "R": ".-.", + "S": "...", + "T": "-", + "U": "..-", + "V": "...-", + "W": ".--", + "X": "-..-", + "Y": "-.--", + "Z": "--..", + " ": "/", +} + + +# Encode text into binary encoded Morse code +def encode_morse(text): + encoded = "" + for char in text.upper(): + if char in morse_code: + morse = morse_code[char] + bits = [] + for symbol in morse: + if symbol == ".": + bits.extend(["1", "0"]) + elif symbol == "-": + bits.extend(["1" * 3, "0"]) + encoded += "0".join(bits) + "0" + encoded = encoded.rstrip("0") # Remove trailing intra-character gap + return encoded + + +# Define tests +class TestMorseEncoding(unittest.TestCase): + def test_hello_world(self): + encoded_text = encode_morse("HELLO WORLD") + self.assertEqual( + encoded_text, + "1010100011101110111010111000101110100010111010001110101000101011100010111010001110100011101011100010101110001011101000101110100010111010001110100011101011100010111010001110100011101011100010101110001011101", + ) diff --git a/challenge-035/lubos-kolouch/python/ch-2.py b/challenge-035/lubos-kolouch/python/ch-2.py new file mode 100644 index 0000000000..619c51d9e8 --- /dev/null +++ b/challenge-035/lubos-kolouch/python/ch-2.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import re +import unittest + +# Define Morse code mappings +morse_code = { + ".-": "A", + "-...": "B", + "-.-.": "C", + "-..": "D", + ".": "E", + "..-.": "F", + "--.": "G", + "....": "H", + "..": "I", + ".---": "J", + "-.-": "K", + ".-..": "L", + "--": "M", + "-.": "N", + "---": "O", + ".--.": "P", + "--.-": "Q", + ".-.": "R", + "...": "S", + "-": "T", + "..-": "U", + "...-": "V", + ".--": "W", + "-..-": "X", + "-.--": "Y", + "--..": "Z", + "/": " ", +} + + +# Decode binary encoded Morse code +def decode_morse(encoded): + # Split encoded text into words and characters + words = re.findall("0{7}", encoded + "0000000") + letters = [re.findall("0{3}", word + "000") for word in words] + # Convert Morse code to plaintext + plaintext = "" + for word in letters: + for letter in word: + if letter in morse_code: + plaintext += morse_code[letter] + else: + # If the Morse code is badly formed, try to recover by looking one digit ahead + for i in range(1, 4): + lookahead = letter[i:] + if lookahead in morse_code: + plaintext += morse_code[lookahead] + break + else: + # If no valid Morse code sequence can be recovered, treat the character as a space + plaintext += " " + return plaintext diff --git a/challenge-038/lubos-kolouch/perl/ch-1.pl b/challenge-038/lubos-kolouch/perl/ch-1.pl new file mode 100644 index 0000000000..91a9f3d71d --- /dev/null +++ b/challenge-038/lubos-kolouch/perl/ch-1.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl +use strict; +use warnings; +use Test::More tests => 6; + +sub date_finder { + my ($input) = @_; + if ( length($input) != 7 ) { + die "Input must be 7 digits long\n"; + } + + my ( $century_digit, $year_digits, $month_digits, $day_digits ) = + unpack "A1A2A2A2", $input; + + my $century = $century_digit == 1 ? "20" : "19"; + my $year = "$century$year_digits"; + + if ( $month_digits < 1 || $month_digits > 12 ) { + die "Invalid month\n"; + } + + my @days_in_month = ( 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); + if ( $year % 4 == 0 && ( $year % 100 != 0 || $year % 400 == 0 ) ) { + $days_in_month[2] = 29; + } + + if ( $day_digits < 1 || $day_digits > $days_in_month[$month_digits] ) { + die "Invalid day\n"; + } + + return sprintf "%04d-%02d-%02d", $year, $month_digits, $day_digits; +} + +is( date_finder('2230120'), '1923-01-20', 'Test case: valid date' ); +is( date_finder('2230230'), '1923-02-30', 'Test case: invalid day' ); +is( date_finder('2230015'), '1923-00-15', 'Test case: invalid month' ); +is( date_finder('1230229'), '2023-02-29', 'Test case: leap year' ); +is( date_finder('1230228'), '2023-02-28', 'Test case: non-leap year' ); +is( date_finder('1230429'), '2023-04-29', 'Test case: valid date' ); diff --git a/challenge-038/lubos-kolouch/perl/ch-2.pl b/challenge-038/lubos-kolouch/perl/ch-2.pl new file mode 100644 index 0000000000..474afa59b4 --- /dev/null +++ b/challenge-038/lubos-kolouch/perl/ch-2.pl @@ -0,0 +1,120 @@ +use strict; +use warnings; +use Test::More; + +my %tiles = ( + 'A' => [ 1, 8 ], + 'G' => [ 1, 3 ], + 'I' => [ 1, 5 ], + 'S' => [ 1, 7 ], + 'U' => [ 1, 5 ], + 'X' => [ 1, 2 ], + 'Z' => [ 1, 5 ], + 'E' => [ 2, 9 ], + 'J' => [ 2, 3 ], + 'L' => [ 2, 3 ], + 'R' => [ 2, 3 ], + 'V' => [ 2, 3 ], + 'Y' => [ 2, 5 ], + 'F' => [ 3, 3 ], + 'D' => [ 3, 3 ], + 'P' => [ 3, 5 ], + 'W' => [ 3, 5 ], + 'B' => [ 4, 5 ], + 'N' => [ 4, 4 ], + 'T' => [ 5, 5 ], + 'O' => [ 5, 3 ], + 'H' => [ 5, 3 ], + 'M' => [ 5, 4 ], + 'C' => [ 5, 4 ], + 'K' => [ 10, 2 ], + 'Q' => [ 10, 2 ] +); + +my @hand = draw_tiles(7); +print "Your hand: @hand\n"; +my $word = get_word(@hand); +my $score = calculate_score($word); +print "Your word: $word\n"; +print "Score: $score\n"; + +sub draw_tiles { + my ($num_tiles) = @_; + my @tiles; + for my $i ( 1 .. $num_tiles ) { + my $tile = get_random_tile(); + push @tiles, $tile; + } + return @tiles; +} + +sub get_random_tile { + my $total_tiles = 0; + for my $letter ( keys %tiles ) { + $total_tiles += $tiles{$letter}[1]; + } + my $rand_num = int( rand($total_tiles) ) + 1; + for my $letter ( keys %tiles ) { + if ( $rand_num <= $tiles{$letter}[1] ) { + $tiles{$letter}[1]--; + return $letter; + } + else { + $rand_num -= $tiles{$letter}[1]; + } + } +} + +sub get_word { + my (@hand) = @_; + print "Enter a word using the tiles in your hand: "; + chomp( my $word = <STDIN> ); + while ( !is_valid_word( $word, @hand ) ) { + print "Invalid word. Try again: "; + chomp( $word = <STDIN> ); + } + return uc($word); +} + +sub is_valid_word { + my ( $word, @hand ) = @_; + my %hand_count; + for my $tile (@hand) { + $hand_count{$tile}++; + } + + for my $char ( split //, $word ) { + if ( !$hand_count{$char}-- ) { + return 0; + } + } + + return length($word) > 0; +} + +sub calculate_score { + my ($word) = @_; + my $score = 0; + + for my $char ( split //, $word ) { + if ( exists( $tiles{$char} ) ) { + $score += $tiles{$char}[0]; + } + else { + die "Invalid character in word: $char\n"; + } + } + + return $score; +} + +# Tests +is( is_valid_word( 'CAT', ( 'C', 'A', 'T' ) ), 1 ); +is( is_valid_word( 'DOG', ( 'D', 'O', 'G' ) ), 1 ); +is( is_valid_word( 'CAT', ( 'C', 'A' ) ), 0 ); +is( is_valid_word( 'DOG', ( 'D', 'O' ) ), 0 ); + +is( calculate_score('CAT'), 8 ); +is( calculate_score('DOG'), 6 ); + +done_testing(); diff --git a/challenge-038/lubos-kolouch/python/ch-1.py b/challenge-038/lubos-kolouch/python/ch-1.py new file mode 100644 index 0000000000..b42d45790f --- /dev/null +++ b/challenge-038/lubos-kolouch/python/ch-1.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from datetime import datetime + + +def date_finder(input_str): + if len(input_str) != 7: + raise ValueError("Input must be 7 digits long") + + century_digit = input_str[0] + year_digits = input_str[1:3] + month_digits = input_str[3:5] + day_digits = input_str[5:7] + + century = "20" if century_digit == "1" else "19" + year = f"{century}{year_digits}" + + if int(month_digits) < 1 or int(month_digits) > 12: + raise ValueError("Invalid month") + + try: + datetime.strptime(f"{year}-{month_digits}-{day_digits}", "%Y-%m-%d") + except ValueError: + raise ValueError("Invalid day") + + return f"{year}-{month_digits}-{day_digits}" + + +print(date_finder("2230120")) # 1923-01-20 diff --git a/challenge-038/lubos-kolouch/python/ch-2.py b/challenge-038/lubos-kolouch/python/ch-2.py new file mode 100644 index 0000000000..6d330ed840 --- /dev/null +++ b/challenge-038/lubos-kolouch/python/ch-2.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import random + +tiles = { + "A": [1, 8], + "G": [1, 3], + "I": [1, 5], + "S": [1, 7], + "U": [1, 5], + "X": [1, 2], + "Z": [1, 5], + "E": [2, 9], + "J": [2, 3], + "L": [2, 3], + "R": [2, 3], + "V": [2, 3], + "Y": [2, 5], + "F": [3, 3], + "D": [3, 3], + "P": [3, 5], + "W": [3, 5], + "B": [4, 5], + "N": [4, 4], + "T": [5, 5], + "O": [5, 3], + "H": [5, 3], + "M": [5, 4], + "C": [5, 4], + "K": [10, 2], + "Q": [10, 2], +} + + +def draw_tiles(num_tiles): + tiles_drawn = [] + for i in range(num_tiles): + tile = get_random_tile() + tiles_drawn.append(tile) + return tiles_drawn + + +def get_random_tile(): + total_tiles = sum([tiles[letter][1] for letter in tiles]) + rand_num = random.randint(1, total_tiles) + for letter in tiles: + if rand_num <= tiles[letter][1]: + tiles[letter][1] -= 1 + return letter + else: + rand_num -= tiles[letter][1] + + +def get_word(hand): + word = input("Enter a word using the tiles in your hand: ").upper() + while not is_valid_word(word, hand): + word = input("Invalid word. Try again: ").upper() + return word + + +def is_valid_word(word, hand): + hand_count = {} + for tile in hand: + if tile in hand_count: + hand_count[tile] += 1 + else: + hand_count[tile] = 1 + + for char in word: + if char in hand_count and hand_count[char] > 0: + hand_count[char] -= 1 + else: + return False + + return len(word) > 0 + + +def calculate_score(word): + score = 0 + for char in word: + if char in tiles: + score += tiles[char][0] + else: + raise ValueError(f"Invalid character in word: {char}") + + return score + + +hand = draw_tiles(7) +print(f"Your hand: {' '.join(hand)}") +word = get_word(hand) +score = calculate_score(word) +print(f"Your word: {word}") +print(f"Score: {score}") diff --git a/challenge-042/lubos-kolouch/perl/ch-1.pl b/challenge-042/lubos-kolouch/perl/ch-1.pl new file mode 100644 index 0000000000..49c8bc9d49 --- /dev/null +++ b/challenge-042/lubos-kolouch/perl/ch-1.pl @@ -0,0 +1,19 @@ +use strict; +use warnings; +use Test::More; + +# Convert a decimal number to octal +sub decimal_to_octal { + my $decimal = shift; + return sprintf( "%o", $decimal ); +} + +# Test the decimal to octal conversion function +is( decimal_to_octal(0), '0', '0 is converted to 0' ); +is( decimal_to_octal(1), '1', '1 is converted to 1' ); +is( decimal_to_octal(2), '2', '2 is converted to 2' ); +is( decimal_to_octal(7), '7', '7 is converted to 7' ); +is( decimal_to_octal(8), '10', '8 is converted to 10' ); +is( decimal_to_octal(50), '62', '50 is converted to 62' ); + +done_testing(); diff --git a/challenge-042/lubos-kolouch/perl/ch-2.pl b/challenge-042/lubos-kolouch/perl/ch-2.pl new file mode 100644 index 0000000000..391570f485 --- /dev/null +++ b/challenge-042/lubos-kolouch/perl/ch-2.pl @@ -0,0 +1,47 @@ +use strict; +use warnings; +use List::Util qw(shuffle); +use Test::More tests => 5; + +# Generate a random string of brackets +sub generate_bracket_string { + my $length = shift; + my @brackets = ( '(', ')' ); + my @shuffled_brackets = shuffle(@brackets); + return join( '', @shuffled_brackets[ 0 .. $length - 1 ] ); +} + +# Check if a string has balanced brackets +sub is_balanced { + my $bracket_string = shift; + my @stack = (); + for my $bracket ( split( //, $bracket_string ) ) { + if ( $bracket eq '(' ) { + push( @stack, $bracket ); + } + elsif ( $bracket eq ')' ) { + if ( @stack == 0 ) { + return 0; + } + pop(@stack); + } + } + return @stack == 0; +} + +# Test the is_balanced function +ok( is_balanced(''), 'Empty string is balanced' ); +ok( is_balanced('()'), 'Simple brackets are balanced' ); +ok( is_balanced('(())'), 'Nested brackets are balanced' ); +ok( !is_balanced('(('), 'Unbalanced brackets are not balanced' ); +ok( !is_balanced('())'), 'Unbalanced brackets are not balanced' ); + +# Generate a random string of brackets and check if it has balanced brackets +my $bracket_string = generate_bracket_string(10); +print "Bracket string: $bracket_string\n"; +if ( is_balanced($bracket_string) ) { + print "The bracket string is balanced\n"; +} +else { + print "The bracket string is not balanced\n"; +} diff --git a/challenge-042/lubos-kolouch/python/ch-1.py b/challenge-042/lubos-kolouch/python/ch-1.py new file mode 100644 index 0000000000..d1cb5c5c46 --- /dev/null +++ b/challenge-042/lubos-kolouch/python/ch-1.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import unittest + + +def decimal_to_octal(decimal: int) -> str: + """Converts a decimal number to an octal string. + + Args: + decimal: The decimal number to convert. + + Returns: + The octal string representation of the decimal number. + """ + return oct(decimal)[2:] + + +class TestDecimalToOctal(unittest.TestCase): + def test_zero(self) -> None: + self.assertEqual(decimal_to_octal(0), "0") + + def test_single_digit(self) -> None: + self.assertEqual(decimal_to_octal(5), "5") + + def test_multiple_digits(self) -> None: + self.assertEqual(decimal_to_octal(50), "62") + + +if __name__ == "__main__": + unittest.main() + +for i in range(0, 51): + octal = decimal_to_octal(i) + print(f"Decimal {i} = Octal {octal}") diff --git a/challenge-042/lubos-kolouch/python/ch-2.py b/challenge-042/lubos-kolouch/python/ch-2.py new file mode 100644 index 0000000000..9fd40978cb --- /dev/null +++ b/challenge-042/lubos-kolouch/python/ch-2.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import unittest +import random + + +def generate_bracket_string(length: int) -> str: + """Generates a random string of ( and ) brackets of the specified length. + + Args: + length: The length of the bracket string to generate. + + Returns: + The generated bracket string. + """ + brackets = ["(", ")"] + return "".join(random.choices(brackets, k=length)) + + +def is_balanced(bracket_string: str) -> bool: + """Checks if a string has balanced brackets. + + Args: + bracket_string: The string to check. + + Returns: + True if the string has balanced brackets, False otherwise. + """ + stack = [] + for bracket in bracket_string: + if bracket == "(": + stack.append(bracket) + elif bracket == ")": + if len(stack) == 0: + return False + stack.pop() + return len(stack) == 0 + + +class TestIsBalanced(unittest.TestCase): + def test_empty_string(self) -> None: + self.assertTrue(is_balanced("")) + + def test_single_opening_bracket(self) -> None: + self.assertFalse(is_balanced("(")) + + def test_single_closing_bracket(self) -> None: + self.assertFalse(is_balanced(")")) + + def test_balanced_string(self) -> None: + self.assertTrue(is_balanced("(())()")) + + def test_unbalanced_string(self) -> None: + self.assertFalse(is_balanced("(()))")) + + +if __name__ == "__main__": + unittest.main() + +bracket_string = generate_bracket_string(10) +print(f"Bracket string: {bracket_string}") +if is_balanced(bracket_string): + print("The bracket string is balanced") +else: + print("The bracket string is not balanced") |
