DEV Community

Simon Green
Simon Green

Posted on

Weekly Challenge: Equalling the score

Weekly Challenge 336

Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. It's a great way for us all to practice some coding.

Challenge, My solutions

Task 1: Equal Group

Task

You are given an array of integers.

Write a script to return true if the given array can be divided into one or more groups: each group must be of the same size as the others, with at least two members, and with all members having the same value.

My solution

Like usual with these challenges, I read the tasks on Monday, but actually write them in the weekend. Originally, I thought this was going to be straight forward. Count the frequency of each integer, and make sure all frequencies are divisible by the lowest one. And that does work for the examples given.

It then occurred to me during the week that this wouldn't work for four of one integer and six of a different one. Back to the drawing board.

For this task, I start by calculating the frequency of each integer. As we only care about the frequency and not the actual integer, I call the values() method, which returns a list (array in Perl) of frequencies.

from collections import Counter

def equal_group(ints: list) -> bool:
    freq = Counter(ints).values()
Enter fullscreen mode Exit fullscreen mode

GitHub Copilot taught me a nice trick I didn't know about for the Perl solution. You can use an inline foreach call to achieve this in fewer lines. Thanks Copilot.

    my %freq = ();
    $freq{$_}++ foreach @ints;
    my @values = values %freq;
Enter fullscreen mode Exit fullscreen mode

If any value only occurs once, we can return false immediately, as no solution is possible.

    if min(freq) == 1:
        return False
Enter fullscreen mode Exit fullscreen mode

I then use an iterator called i which starts at 2 to the maximum frequency. If all values in freq are evenly divisible by i, I return true. If the iterator is exhausted, I return false.

    for i in range(2, max(freq) + 1):
        if all(f % i == 0 for f in freq):
            return True

    return False
Enter fullscreen mode Exit fullscreen mode

The Perl code follows the same logic.

Examples

$ ./ch-1.py 1 1 2 2 2 2
True

$ ./ch-1.py 1 1 1 2 2 2 3 3
False

$ ./ch-1.py 5 5 5 5 5 5 7 7 7 7 7 7
True

$ ./ch-1.py 1 2 3 4
False

$ ./ch-1.py 8 8 9 9 10 10 11 11
True

Enter fullscreen mode Exit fullscreen mode

Task 2: Final Score

Task

You are given an array of scores by a team.

Write a script to find the total score of the given team. The score can be any integer, +, C or D. The + adds the sum of previous two scores. The score C invalidates the previous score. The score D will double the previous score.

My solution

It's challenges like this one where GitHub Copilot really shows its powers. Like usual, I start by writing my test.py file to validate the code against the provided examples.

Bu the time I was ready to write the code, Copilot basically wrote it for me. I did change the syntax slightly (mostly to raise errors when unexpected input was provided, but the Copilot generated code would have done the right thing for any valid input.

As Copilot explains:

The function final_score ... processes a list of string commands representing scores and operations, and computes the final total score. Here’s how it works:

  • It uses a stack [called] score_stack to keep track of valid scores.
  • For each item in the input list:
    • If the item is C, it removes (undoes) the last score.
    • If the item is D, it doubles the last score and adds it as a new score.
    • If the item is +, it adds a new score equal to the sum of the previous two scores.
    • If the item is an integer..., it adds it as a new score.
    • If the item is invalid, it raises an error.
  • At the end, it returns the sum of all scores in the stack.

The Python code is

def final_score(scores: list[str]) -> int:
    score_stack = []

    for score in scores:
        if score == "C":
            if not score_stack:
                raise ValueError("No scores to remove for 'C' operation")
            score_stack.pop()
        elif score == "D":
            if not score_stack:
                raise ValueError("No scores to double for 'D' operation")
            score_stack.append(2 * score_stack[-1])
        elif score == "+":
            if len(score_stack) < 2:
                raise ValueError("Not enough scores to sum for '+' operation")
            score_stack.append(score_stack[-1] + score_stack[-2])
        elif re.match(r"^-?\d+$", score):
            score_stack.append(int(score))
        else:
            raise ValueError(f"Invalid score entry: {score}")

    return sum(score_stack)
Enter fullscreen mode Exit fullscreen mode

The Perl code follows the same logic.

Examples

$ ./ch-2.py 5 2 C D +
30

$ ./ch-2.py 5 -2 4 C D 9 + +
27

$ ./ch-2.py 7 D D C + 3
45

$ ./ch-2.py -5 -10 + D C +
-55

$ ./ch-2.py 3 6 + D C 8 + D -2 C +
128
Enter fullscreen mode Exit fullscreen mode

Top comments (0)