aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Goodnight <ian.goodnight@scythe.io>2024-06-16 14:44:45 -0400
committerIan Goodnight <ian.goodnight@scythe.io>2024-06-16 14:44:45 -0400
commitd87e83206ea21bc2290ce459ffba878e94e49f95 (patch)
tree1cdd10ba3c58cf4925668c14a886e63041aa8634
parent194611acf9d0f7f165ac0ec595774b2c6fd5f413 (diff)
downloadperlweeklychallenge-club-d87e83206ea21bc2290ce459ffba878e94e49f95.tar.gz
perlweeklychallenge-club-d87e83206ea21bc2290ce459ffba878e94e49f95.tar.bz2
perlweeklychallenge-club-d87e83206ea21bc2290ce459ffba878e94e49f95.zip
week 273
-rw-r--r--challenge-273/iangoodnight/README.md1
-rw-r--r--challenge-273/iangoodnight/perl/README.md320
-rw-r--r--challenge-273/iangoodnight/perl/t/task1.t37
-rw-r--r--challenge-273/iangoodnight/perl/t/task2.t27
-rw-r--r--challenge-273/iangoodnight/perl/task1.pm201
-rw-r--r--challenge-273/iangoodnight/perl/task2.pm157
-rw-r--r--challenge-273/iangoodnight/python/.gitignore1
-rw-r--r--challenge-273/iangoodnight/python/README.md244
-rw-r--r--challenge-273/iangoodnight/python/__init__.py0
-rw-r--r--challenge-273/iangoodnight/python/requirements.txt4
-rw-r--r--challenge-273/iangoodnight/python/task1.py85
-rw-r--r--challenge-273/iangoodnight/python/task2.py61
-rw-r--r--challenge-273/iangoodnight/python/tests/__init__.py7
-rw-r--r--challenge-273/iangoodnight/python/tests/test_task1.py22
-rw-r--r--challenge-273/iangoodnight/python/tests/test_task2.py10
-rw-r--r--challenge-273/iangoodnight/typescript/README.md256
-rw-r--r--challenge-273/iangoodnight/typescript/__tests__/task1.test.ts10
-rw-r--r--challenge-273/iangoodnight/typescript/__tests__/task2.test.ts19
-rw-r--r--challenge-273/iangoodnight/typescript/jest.config.json4
-rw-r--r--challenge-273/iangoodnight/typescript/package-lock.json3598
-rw-r--r--challenge-273/iangoodnight/typescript/package.json11
-rw-r--r--challenge-273/iangoodnight/typescript/task1.ts78
-rw-r--r--challenge-273/iangoodnight/typescript/task2.ts55
-rw-r--r--challenge-273/iangoodnight/typescript/tsconfig.json35
24 files changed, 5243 insertions, 0 deletions
diff --git a/challenge-273/iangoodnight/README.md b/challenge-273/iangoodnight/README.md
index 2a4a23a28c..482703debb 100644
--- a/challenge-273/iangoodnight/README.md
+++ b/challenge-273/iangoodnight/README.md
@@ -1 +1,2 @@
Solution by Ian Goodnight
+
diff --git a/challenge-273/iangoodnight/perl/README.md b/challenge-273/iangoodnight/perl/README.md
new file mode 100644
index 0000000000..6634a635ac
--- /dev/null
+++ b/challenge-273/iangoodnight/perl/README.md
@@ -0,0 +1,320 @@
+# Perl Weekly Challenge - 273
+
+Welcome to [Week #273][0] of [The Weekly Challenge][1].
+
+## Task 1: Percentage of Character
+
+**Submitted by:** [Mohammad Sajid Anwar][2]
+
+You are given a string, `$str` and a character `$char`.
+
+Write a script to return the percentage, nearest whole, of given character in
+the given string.
+
+**Example 1**
+
+```
+Input: $str = "perl", $char = "e"
+Output: 25
+```
+
+**Example 2**
+
+```
+Input: $str = "java", $char = "a"
+Output: 50
+```
+
+**Example 3**
+
+```
+Input: $str = "python", $char = "m"
+Output: 0
+```
+
+**Example 4**
+
+```
+Input: $str = "ada", $char = "a"
+Output: 67
+```
+
+**Example 5**
+
+```
+Input: $str = "ballerina", $char = "l"
+Output: 22
+```
+
+**Example 6**
+
+```
+Input: $str = "analitik", $char = "k"
+Output: 13
+```
+
+### Solution
+
+Our solution is implemented as the [task1.pm][3] module. The module provides a
+single exported function `percentage_of_character` that takes two arguments as
+described in the task and returns the percentage of the given character in the
+given string.
+
+```perl
+use strict;
+use warnings;
+use autodie;
+
+use Exporter;
+use Readonly;
+
+our $VERSION = '1.0.0';
+
+our @EXPORT_OK = qw(percentage_of_character);
+
+Readonly::Scalar my $EMPTY => q{}; # for splitting the string
+Readonly::Scalar my $PERCENTAGE_FACTOR => 100; # for converting decimal
+Readonly::Scalar my $ROUNDING_THRESHOLD => 0.5; # for rounding the percentage
+
+sub percentage_of_character {
+ my ( $str, $char ) = @_;
+
+ # string length ends up as the denominator of our percentage calculation
+ my $string_length = length $str // 0;
+
+ # if the string is empty, return 0 rather than dividing by zero
+ if ( $string_length == 0 || !defined $char ) {
+ return 0;
+ }
+
+ # grab characters as a list
+ my @characters = split $EMPTY, $str;
+
+ # filter down to the characters that match the given character
+ my @matching_characters = grep { $_ eq $char } @characters;
+
+ # count the number of matching characters
+ my $matching_characters_count = scalar @matching_characters;
+
+ # calculate the percentage as a decimal
+ my $decimal_percentage = $matching_characters_count / $string_length;
+
+ # convert the decimal to a percentage
+ my $percentage = $decimal_percentage * $PERCENTAGE_FACTOR;
+
+ # round the percentage to the nearest whole number
+ my $rounded_percentage = int( $percentage + $ROUNDING_THRESHOLD );
+
+ # return the rounded percentage as the result
+ return $rounded_percentage;
+}
+
+1;
+```
+
+This solution could be a lot more concise, but we have opted for clarity and
+readability (possibly at the expense of brevity). For the most part, the
+comments in the code should be self-explanatory. We have used the `Readonly`
+module to define some constants that are used in the calculation of the
+percentage. The `percentage_of_character` function takes the string and the
+character as arguments and returns the percentage of the character in the string
+as an integer.
+
+### Testing
+
+We have included a test script to verify the correctness of our solution. The
+test script uses the `Test::More` module to run a series of tests against the
+`percentage_of_character` function. The test script is as follows:
+
+```perl
+use strict;
+use warnings;
+use autodie;
+
+use Readonly;
+use Test::More;
+
+use lib qw( . );
+
+use Task1 qw(percentage_of_character);
+
+Readonly::Scalar my $EMPTY_STR => q{};
+
+subtest 'Examples' => sub {
+ plan tests => 6;
+
+ is( percentage_of_character( 'perl', 'e' ), 25, 'Example 1' );
+ is( percentage_of_character( 'java', 'a' ), 50, 'Example 2' );
+ is( percentage_of_character( 'python', 'm' ), 0, 'Example 3' );
+ is( percentage_of_character( 'ada', 'a' ), 67, 'Example 4' );
+ is( percentage_of_character( 'ballerina', 'l' ), 22, 'Example 5' );
+ is( percentage_of_character( 'analitik', 'k' ), 13, 'Example 6' );
+};
+
+subtest 'Additional tests' => sub {
+ plan tests => 7;
+
+ is( percentage_of_character( 'perl', 'x' ), 0, 'Character not found' );
+ is( percentage_of_character( 'perl', 2 ), 0, 'Input other than strings' );
+ is( percentage_of_character( 2, 'e' ), 0, 'Input other than strings' );
+ is( percentage_of_character( $EMPTY_STR, 'e' ), 0, 'Empty string' );
+ is( percentage_of_character( 'perl', $EMPTY_STR ), 0, 'Empty character' );
+ is( percentage_of_character('perl'), 0, 'No character argument' );
+ is( percentage_of_character(), 0, 'No input' );
+};
+
+done_testing();
+```
+
+You can run the test script using the following command (assumes the `prove`
+utility is available):
+
+```bash
+prove ./t/task1.t
+```
+
+## Task 2: B After A
+
+**Submitted by:** [Mohammad Sajid Anwar][2]
+
+You are given a string, `$str`.
+
+Write a script to return `true` if there is at least one `b`, and no `a` appears
+after the first `b`.
+
+**Example 1**
+
+```
+Input: $str = "aabb"
+Output: true
+```
+
+**Example 2**
+
+```
+Input: $str = "abab"
+Output: false
+```
+
+**Example 3**
+
+```
+Input: $str = "aaa"
+Output: false
+```
+
+**Example 4**
+
+```
+Input: $str = "bbb"
+Output: true
+```
+
+### Solution
+
+Our solution is implemented as the [task2.pm][4] module. The module provides a
+single exported function `b_after_a` that takes a single argument as described
+in the task and returns a boolean value indicating whether the given string
+satisfies the conditions of the task.
+
+```perl
+
+use strict;
+use warnings;
+use autodie;
+use Exporter;
+
+our $VERSION = '1.0.0';
+
+our @EXPORT_OK = qw(b_after_a);
+
+sub b_after_a {
+ my $str = shift // q{};
+
+ # Regular expression to match the string
+ ## no critic (RegularExpressions::RequireDotMatchAnything)
+ my $re = qr{
+ ^ # Start of the string
+ [^b]* # Match any character except 'b' zero or more times
+ b+ # Match 'b' one or more times
+ [^a]* # Match any character except 'a' zero or more times
+ $ # End of the string
+ }mx;
+ ## use critic
+ # Test the string against the regular expression and return the result
+ if ( $str =~ $re ) {
+ return 1;
+ }
+ return 0;
+}
+
+1;
+```
+
+Our function uses a regular expression to match the against the conditions input
+string. Arguably, the regular expression could be more concise, but despite the
+prompt example describing all the input strings as being comprised of only 'a'
+and 'b' characters, the initial problem statement does not explicitly constrain
+the input to only those characters. Therefore, we have opted for a more general
+regular expression that will matches strings that contain any any character
+after the first 'b' that is not an 'a'. Perlcritic has reminded us that in many
+regex implementations, the dot character '.' is a wildcard that matches any
+character except a newline. This is certainly worth considering, but in this
+particular case, we do not use the dot character in our regular expression. We
+opt to disable this particular critic rule for this regular expression rather
+than add a superfluous flag to the regular expression.
+
+### Testing
+
+We have included a test script to verify the correctness of our solution. The
+test script uses the `Test::More` module to run a series of tests against the
+`b_after_a` function. The test script is as follows:
+
+```perl
+use strict;
+use warnings;
+use autodie;
+use Test::More;
+
+use lib qw( . );
+
+use task2 qw(b_after_a);
+
+subtest 'Examples' => sub {
+ plan tests => 4;
+
+ is( b_after_a('aabb'), 1, 'Example 1' );
+ is( b_after_a('abab'), 0, 'Example 2' );
+ is( b_after_a('aaa'), 0, 'Example 3' );
+ is( b_after_a('bbb'), 1, 'Example 4' );
+};
+
+subtest 'Additional tests' => sub {
+ plan tests => 3;
+
+ is( b_after_a('abbc'), 1, 'Characters other than "a" after "b"' );
+ is( b_after_a(2), 0, 'Input other than strings' );
+ is( b_after_a(), 0, 'No input' );
+};
+
+done_testing();
+```
+
+You can run the test script using the following command (assumes the `prove`
+utility is available):
+
+```bash
+prove ./t/task2.t
+```
+
+You can run both test scripts using the following command:
+
+```bash
+prove -r
+```
+
+[0]: https://perlweeklychallenge.org/blog/perl-weekly-challenge-272/
+[1]: https://perlweeklychallenge.org
+[2]: https://manwar.org/
+[3]: ./task1.pm
+[4]: ./task2.pm
diff --git a/challenge-273/iangoodnight/perl/t/task1.t b/challenge-273/iangoodnight/perl/t/task1.t
new file mode 100644
index 0000000000..5c134834d3
--- /dev/null
+++ b/challenge-273/iangoodnight/perl/t/task1.t
@@ -0,0 +1,37 @@
+use strict;
+use warnings;
+use autodie;
+
+use Readonly;
+use Test::More;
+
+use lib qw( . );
+
+use Task1 qw(percentage_of_character);
+
+Readonly::Scalar my $EMPTY_STR => q{};
+
+subtest 'Examples' => sub {
+ plan tests => 6;
+
+ is( percentage_of_character( 'perl', 'e' ), 25, 'Example 1' );
+ is( percentage_of_character( 'java', 'a' ), 50, 'Example 2' );
+ is( percentage_of_character( 'python', 'm' ), 0, 'Example 3' );
+ is( percentage_of_character( 'ada', 'a' ), 67, 'Example 4' );
+ is( percentage_of_character( 'ballerina', 'l' ), 22, 'Example 5' );
+ is( percentage_of_character( 'analitik', 'k' ), 13, 'Example 6' );
+};
+
+subtest 'Additional tests' => sub {
+ plan tests => 7;
+
+ is( percentage_of_character( 'perl', 'x' ), 0, 'Character not found' );
+ is( percentage_of_character( 'perl', 2 ), 0, 'Input other than strings' );
+ is( percentage_of_character( 2, 'e' ), 0, 'Input other than strings' );
+ is( percentage_of_character( $EMPTY_STR, 'e' ), 0, 'Empty string' );
+ is( percentage_of_character( 'perl', $EMPTY_STR ), 0, 'Empty character' );
+ is( percentage_of_character('perl'), 0, 'No character argument' );
+ is( percentage_of_character(), 0, 'No input' );
+};
+
+done_testing();
diff --git a/challenge-273/iangoodnight/perl/t/task2.t b/challenge-273/iangoodnight/perl/t/task2.t
new file mode 100644
index 0000000000..92563be8e3
--- /dev/null
+++ b/challenge-273/iangoodnight/perl/t/task2.t
@@ -0,0 +1,27 @@
+use strict;
+use warnings;
+use autodie;
+use Test::More;
+
+use lib qw( . );
+
+use task2 qw(b_after_a);
+
+subtest 'Examples' => sub {
+ plan tests => 4;
+
+ is( b_after_a('aabb'), 1, 'Example 1' );
+ is( b_after_a('abab'), 0, 'Example 2' );
+ is( b_after_a('aaa'), 0, 'Example 3' );
+ is( b_after_a('bbb'), 1, 'Example 4' );
+};
+
+subtest 'Additional tests' => sub {
+ plan tests => 3;
+
+ is( b_after_a('abbc'), 1, 'Characters other than "a" after "b"' );
+ is( b_after_a(2), 0, 'Input other than strings' );
+ is( b_after_a(), 0, 'No input' );
+};
+
+done_testing();
diff --git a/challenge-273/iangoodnight/perl/task1.pm b/challenge-273/iangoodnight/perl/task1.pm
new file mode 100644
index 0000000000..645852ce09
--- /dev/null
+++ b/challenge-273/iangoodnight/perl/task1.pm
@@ -0,0 +1,201 @@
+#!/usr/bin/perl
+
+=begin comment
+
+## Task 1: Percentage of Character
+
+**Submitted by:** [Mohammad Sajid Anwar][1]
+
+You are given a string, `$str` and a character `$char`.
+
+Write a script to return the percentage, nearest whole, of given character in
+the given string.
+
+**Example 1**
+
+```
+Input: $str = "perl", $char = "e"
+Output: 25
+```
+
+**Example 2**
+
+```
+Input: $str = "java", $char = "a"
+Output: 50
+```
+
+**Example 3**
+
+```
+Input: $str = "python", $char = "m"
+Output: 0
+```
+
+**Example 4**
+
+```
+Input: $str = "ada", $char = "a"
+Output: 67
+```
+
+**Example 5**
+
+```
+Input: $str = "ballerina", $char = "l"
+Output: 22
+```
+
+**Example 6**
+
+```
+Input: $str = "analitik", $char = "k"
+Output: 13
+```
+
+[1]: https://manwar.org/
+
+=end comment
+=cut
+
+use strict;
+use warnings;
+use autodie;
+
+use Exporter;
+use Readonly;
+
+our $VERSION = '1.0.0';
+
+our @EXPORT_OK = qw(percentage_of_character);
+
+Readonly::Scalar my $EMPTY => q{}; # for splitting the string
+Readonly::Scalar my $PERCENTAGE_FACTOR => 100; # for converting decimal
+Readonly::Scalar my $ROUNDING_THRESHOLD => 0.5; # for rounding the percentage
+
+sub percentage_of_character {
+ my ( $str, $char ) = @_;
+
+ # string length ends up as the denominator of our percentage calculation
+ my $string_length = length $str // 0;
+
+ # if the string is empty, return 0 rather than dividing by zero
+ if ( $string_length == 0 || !defined $char ) {
+ return 0;
+ }
+
+ # grab characters as a list
+ my @characters = split $EMPTY, $str;
+
+ # filter down to the characters that match the given character
+ my @matching_characters = grep { $_ eq $char } @characters;
+
+ # count the number of matching characters
+ my $matching_characters_count = scalar @matching_characters;
+
+ # calculate the percentage as a decimal
+ my $decimal_percentage = $matching_characters_count / $string_length;
+
+ # convert the decimal to a percentage
+ my $percentage = $decimal_percentage * $PERCENTAGE_FACTOR;
+
+ # round the percentage to the nearest whole number
+ my $rounded_percentage = int( $percentage + $ROUNDING_THRESHOLD );
+
+ # return the rounded percentage as the result
+ return $rounded_percentage;
+}
+
+1;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+Task 1: Percentage of Character
+
+=head1 VERSION
+
+This documentation refers to Task 1: Percentage of Character version 1.0.0
+
+=head1 EXPORTS
+
+The function C<percentage_of_character> is exported by default.
+
+=head1 USAGE
+
+ use strict;
+ use warnings;
+ use feature qw(say);
+ use Task1 qw(percentage_of_character);
+
+ my $str = 'perl';
+ my $char = 'e';
+ say percentage_of_character( $str, $char ); # output: 25
+
+=head1 DESCRIPTION
+
+Given a string, C<$str> and a character C<$char>, the function
+C<percentage_of_character> returns the percentage, rounded to the nearest whole
+number, of the given character in the given string.
+
+=head1 REQUIRED ARGUMENTS
+
+=over 4
+
+=item C<$str>
+
+A string.
+
+=item C<$char>
+
+A character.
+
+=back
+
+=head1 OPTIONS
+
+None.
+
+=head1 DIAGNOSTICS
+
+None.
+
+=head1 EXIT STATUS
+
+None.
+
+=head1 CONFIGURATION
+
+None.
+
+=head1 DEPENDENCIES
+
+=over 4
+
+=item * Exporter
+
+=item * Readonly
+
+=back
+
+=head1 INCOMPATIBILITIES
+
+None reported.
+
+=head1 BUGS AND LIMITATIONS
+
+None reported.
+
+=head1 AUTHOR
+
+Ian Goodnight
+
+=head1 LICENSE AND COPYRIGHT
+
+This software is released under the terms of the GNU General Public License
+Version 3.
+
+=cut
diff --git a/challenge-273/iangoodnight/perl/task2.pm b/challenge-273/iangoodnight/perl/task2.pm
new file mode 100644
index 0000000000..14ee6b18de
--- /dev/null
+++ b/challenge-273/iangoodnight/perl/task2.pm
@@ -0,0 +1,157 @@
+#!/usr/bin/perl
+
+=begin comment
+
+## Task 2: B After A
+
+**Submitted by:** [Mohammad Sajid Anwar][2]
+
+You are given a string, `$str`.
+
+Write a script to return `true` if there is at least one `b`, and no `a` appears
+after the first `b`.
+
+**Example 1**
+
+```
+Input: $str = "aabb"
+Output: true
+```
+
+**Example 2**
+
+```
+Input: $str = "abab"
+Output: false
+```
+
+**Example 3**
+
+```
+Input: $str = "aaa"
+Output: false
+```
+
+**Example 4**
+
+```
+Input: $str = "bbb"
+Output: true
+```
+
+[2]: https://manwar.org/
+
+=end comment
+=cut
+
+use strict;
+use warnings;
+use autodie;
+use Exporter;
+
+our $VERSION = '1.0.0';
+
+our @EXPORT_OK = qw(b_after_a);
+
+sub b_after_a {
+ my $str = shift // q{};
+
+ # Regular expression to match the string
+ ## no critic (RegularExpressions::RequireDotMatchAnything)
+ my $re = qr{
+ ^ # Start of the string
+ [^b]* # Match any character except 'b' zero or more times
+ b+ # Match 'b' one or more times
+ [^a]* # Match any character except 'a' zero or more times
+ $ # End of the string
+ }mx;
+ ## use critic
+ # Test the string against the regular expression and return the result
+ if ( $str =~ $re ) {
+ return 1;
+ }
+ return 0;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Task2: B After A
+
+=head1 VERSION
+
+This documentation refers to Task2 version 1.0.0
+
+=head1 EXPORTS
+
+The function L</b_after_a> is exported by default.
+
+=head1 USAGE
+
+ use strict;
+ use warnings;
+ use feature qw(say);
+ use Task2 qw(b_after_a);
+
+ my $str1 = 'aabb';
+ my $str2 = 'abab';
+
+ say b_after_a($str1); # Output: 1
+ say b_after_a($str2); # Output: 0
+
+=head1 DESCRIPTION
+
+Given a string, C<$str>, the function C<b_after_a> returns true if there is at
+least one 'b', and no 'a' appears after the first 'b'.
+
+=head1 REQUIRED ARGUMENTS
+
+=over 4
+
+=item C<$str>
+
+A string.
+
+=back
+
+=head1 OPTIONS
+
+None.
+
+=head1 DIAGNOSTICS
+
+None.
+
+=head1 EXIT STATUS
+
+None.
+
+=head1 CONFIGURATION
+
+None.
+
+=head1 DEPENDENCIES
+
+None.
+
+=head1 INCOMPATIBILITIES
+
+None reported.
+
+=head1 BUGS AND LIMITATIONS
+
+None reported.
+
+=head1 AUTHOR
+
+Ian Goodnight
+
+=head1 LICENSE AND COPYRIGHT
+
+This software is released under the terms of theGNU General Public License
+Version 3.
+
+=cut
diff --git a/challenge-273/iangoodnight/python/.gitignore b/challenge-273/iangoodnight/python/.gitignore
new file mode 100644
index 0000000000..c18dd8d83c
--- /dev/null
+++ b/challenge-273/iangoodnight/python/.gitignore
@@ -0,0 +1 @@
+__pycache__/
diff --git a/challenge-273/iangoodnight/python/README.md b/challenge-273/iangoodnight/python/README.md
new file mode 100644
index 0000000000..31ae6aed6e
--- /dev/null
+++ b/challenge-273/iangoodnight/python/README.md
@@ -0,0 +1,244 @@
+# Perl Weekly Challenge - 273
+
+Welcome to [Week #273][0] of [The Weekly Challenge][1].
+
+## Task 1: Percentage of Character
+
+**Submitted by:** [Mohammad Sajid Anwar][2]
+
+You are given a string, `$str` and a character `$char`.
+
+Write a script to return the percentage, nearest whole, of given character in
+the given string.
+
+**Example 1**
+
+```
+Input: $str = "perl", $char = "e"
+Output: 25
+```
+
+**Example 2**
+
+```
+Input: $str = "java", $char = "a"
+Output: 50
+```
+
+**Example 3**
+
+```
+Input: $str = "python", $char = "m"
+Output: 0
+```
+
+**Example 4**
+
+```
+Input: $str = "ada", $char = "a"
+Output: 67
+```
+
+**Example 5**
+
+```
+Input: $str = "ballerina", $char = "l"
+Output: 22
+```
+
+**Example 6**
+
+```
+Input: $str = "analitik", $char = "k"
+Output: 13
+```
+
+### Solution
+
+### Testing
+
+Our [solution][3] is intentionally designed to be simple and easy to understand.
+We have defined two constants, `PERCENTAGE_FACTOR` and `ROUNDING_THRESHOLD`, to
+help with the calculation of the percentage. The `percentage_of_character`
+function takes two arguments, `string` and `char`, and returns the percentage of
+the character in the string, rounded to the nearest whole number. Using a
+declarative approach, we first calculate the length of the string and the number
+of times the character appears in the string. We then calculate the percentage
+of the character in the string as a decimal, convert it to a percentage, and
+round it to the nearest whole number using half up rounding. It came as a
+surprise to find that python implements an `even up` rounding by default, which
+could lead to incorrect results. With an `even up` rounding strategy, a value of
+`0.5` would be rounded down to `0`, whereas we want it to be rounded up to `1`.
+The rounding method we have used is known as `half up` rounding, which rounds
+`0.5` up to `1`. The function returns `0` if the string or character are empty.
+
+```python
+PERCENTAGE_FACTOR = 100 # multiply the decimal value by 100 to get percentage
+ROUNDING_THRESHOLD = 0.5 # ensure we are rounding half up, rather than even up
+
+
+def percentage_of_character(string: str, char: str) -> int:
+ """Return the percentage of given character in the given string.
+
+ Args:
+ string: The string to search for the character.
+ char: The character to search for in the string.
+
+ Returns:
+ The percentage of the character in the string, rounded to the nearest
+ whole number.
+ """
+ # Get the length of the string for testing and calculating the percentage
+ string_length = len(string)
+ # Return 0 if the string or character are empty
+ if string_length == 0 or len(char) == 0:
+ return 0
+ # Count the number of times the character appears in the string
+ char_count = string.count(char)
+ # Calculate the percentage of the character in the string as a decimal
+ decimal_percentage = char_count / string_length
+ # Convert the decimal percentage to a percentage
+ percentage = decimal_percentage * PERCENTAGE_FACTOR
+ # Round the percentage to the nearest whole number (half up rounding)
+ rounded_percentage = int(percentage + ROUNDING_THRESHOLD)
+
+ return rounded_percentage
+```
+
+### Testing
+
+We have written a comprehensive test suite to validate our solution. We have
+covered both the base and extra test cases to ensure our solution works as
+expected. Runnning the test suite requires the `pytest` module, which can be
+installed using `pip install pytest`.
+
+```python
+from challenge273.task1 import percentage_of_character
+
+
+def test_examples() -> None:
+ """Test if function returns correct percentage of character"""
+ assert percentage_of_character("perl", "e") == 25
+ assert percentage_of_character("java", "a") == 50
+ assert percentage_of_character("python", "m") == 0
+ assert percentage_of_character("ada", "a") == 67
+ assert percentage_of_character("ballerina", "l") == 22
+ assert percentage_of_character("analitik", "k") == 13
+
+
+def test_empty_string() -> None:
+ """Test if function returns 0 for empty string"""
+ assert percentage_of_character("", "a") == 0
+
+
+def test_empty_character() -> None:
+ """Test if function returns 0 for empty character"""
+ assert percentage_of_character("python", "") == 0
+```
+
+The test suite can be run using the following command:
+
+```bash
+$ pytest test_task1.py
+```
+
+## Task 2: B After A
+
+**Submitted by:** [Mohammad Sajid Anwar][2]
+
+You are given a string, `$str`.
+
+Write a script to return `true` if there is at least one `b`, and no `a` appears
+after the first `b`.
+
+**Example 1**
+
+```
+Input: $str = "aabb"
+Output: true
+```
+
+**Example 2**
+
+```
+Input: $str = "abab"
+Output: false
+```
+
+**Example 3**
+
+```
+Input: $str = "aaa"
+Output: false
+```
+
+**Example 4**
+
+```
+Input: $str = "bbb"
+Output: true
+```
+
+### Solution
+
+Our [solution][4] is simple and easy to understand. The `b_after_a` function
+takes a single argument, `string`, and returns `True` if there is at least one
+`b` in the string and no `a` appears after the first `b`. We first check if
+there is no `b` in the string, in which case we return `False`. We then find the
+index of the first `b` in the string and slice the string after the first `b`.
+Finally, we check if there is no `a` in the slice and return `True` if that is
+the case; otherwise, we return `False`.
+
+```python
+def b_after_a(string: str) -> bool:
+ """
+ Returns `true` if there is at least one `b`, and no `a` appears after the
+ first `b`.
+
+ Args:
+ string: The input string to check for the presence of `b` and `a`.
+
+ Returns:
+ `True` if there is at least one `b`, and no `a` appears after the first
+ `b`; otherwise, `False`.
+ """
+ if "b" not in string: # fails if there is no `b` in the string
+ return False
+ b_index = string.index("b")
+ # grab a slice of the string after the first `b`
+ sliced_after_b = string[b_index + 1:]
+ # check if there is no `a` in the slice
+ return "a" not in sliced_after_b
+```
+
+### Testing
+
+We have written a comprehensive test suite to validate our solution. We have
+covered both the base and extra test cases to ensure our solution works as