aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2023-03-26 12:28:38 +0100
committerGitHub <noreply@github.com>2023-03-26 12:28:38 +0100
commit2860bdf1fac3d5235cd68ede860853e15d69708e (patch)
treea851f3361a3ed808425b940f8623e07465d3f276
parent0268632e64340f543178e3438a8ce741c3b775d4 (diff)
parent2a6bb0ae68aad6f29c807dc4f0423768cc845d9a (diff)
downloadperlweeklychallenge-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.pl57
-rw-r--r--challenge-035/lubos-kolouch/perl/ch-2.pl70
-rw-r--r--challenge-035/lubos-kolouch/python/ch-1.py62
-rw-r--r--challenge-035/lubos-kolouch/python/ch-2.py60
-rw-r--r--challenge-038/lubos-kolouch/perl/ch-1.pl39
-rw-r--r--challenge-038/lubos-kolouch/perl/ch-2.pl120
-rw-r--r--challenge-038/lubos-kolouch/python/ch-1.py30
-rw-r--r--challenge-038/lubos-kolouch/python/ch-2.py95
-rw-r--r--challenge-042/lubos-kolouch/perl/ch-1.pl19
-rw-r--r--challenge-042/lubos-kolouch/perl/ch-2.pl47
-rw-r--r--challenge-042/lubos-kolouch/python/ch-1.py35
-rw-r--r--challenge-042/lubos-kolouch/python/ch-2.py66
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")