diff --git a/exercises/armstrong-numbers/armstrong_numbers.py b/exercises/armstrong-numbers/armstrong_numbers.py index b8829fac575..ee0fef3a215 100644 --- a/exercises/armstrong-numbers/armstrong_numbers.py +++ b/exercises/armstrong-numbers/armstrong_numbers.py @@ -1,2 +1,5 @@ def is_armstrong_number(number): - pass + number_len = len(str(number)) + count_list = [int(i) ** number_len for i in str(number)] + return sum(count_list) == number + diff --git a/exercises/bob/bob.py b/exercises/bob/bob.py index 94a7315112e..19f1f0de52b 100644 --- a/exercises/bob/bob.py +++ b/exercises/bob/bob.py @@ -1,2 +1,11 @@ -def response(hey_bob): - pass +import re + + +def hey(phrase): + phrase = phrase.strip() + if phrase == '': + return 'Fine. Be that way!' + elif phrase.upper() == phrase and re.search("[a-zA-Z]", phrase): + return "Calm down, I know what I'm doing!" if phrase[-1] == '?' else 'Whoa, chill out!' + else: + return "Sure." if phrase[-1] == "?" else "Whatever." diff --git a/exercises/darts/darts.py b/exercises/darts/darts.py index 4ba1b3b935f..f73eacd6865 100644 --- a/exercises/darts/darts.py +++ b/exercises/darts/darts.py @@ -1,2 +1,3 @@ def score(x, y): - pass + distance = x ** 2 + y ** 2 + return 10 if distance <= 1 ** 2 else 5 if distance <= 5 ** 2 else 1 if distance <= 10 ** 2 else 0 diff --git a/exercises/dnd-character/dnd_character.py b/exercises/dnd-character/dnd_character.py index f8ecd30bb88..60631694574 100644 --- a/exercises/dnd-character/dnd_character.py +++ b/exercises/dnd-character/dnd_character.py @@ -1,3 +1,20 @@ +import random + + +def modifier(num): + return int((num - 10) // 2) + + class Character: def __init__(self): - pass + self.strength = self.ability() + self.dexterity = self.ability() + self.constitution = self.ability() + self.intelligence = self.ability() + self.wisdom = self.ability() + self.charisma = self.ability() + self.hitpoints = 10 + modifier(self.constitution) + + def ability(self): + results = [random.randint(1, 6) for i in range(4)] + return sum(results) - results.pop(random.randint(0, 3)) diff --git a/exercises/error-handling/error_handling.py b/exercises/error-handling/error_handling.py index f34ccee1cf0..976d01f545a 100644 --- a/exercises/error-handling/error_handling.py +++ b/exercises/error-handling/error_handling.py @@ -1,14 +1,22 @@ def handle_error_by_throwing_exception(): - pass + raise Exception("fail") def handle_error_by_returning_none(input_data): - pass + try: + return int(input_data) + except ValueError: + return None def handle_error_by_returning_tuple(input_data): - pass + try: + return True, int(input_data) + except ValueError as e: + return False, e.__repr__() def filelike_objects_are_closed_on_exception(filelike_object): - pass + with filelike_object as f: + f.do_something() + diff --git a/exercises/gigasecond/gigasecond.py b/exercises/gigasecond/gigasecond.py index 95fcc6fbceb..c7c171f270f 100644 --- a/exercises/gigasecond/gigasecond.py +++ b/exercises/gigasecond/gigasecond.py @@ -1,2 +1,5 @@ +from datetime import timedelta + + def add(moment): - pass + return moment + timedelta(seconds=10**9) diff --git a/exercises/grains/grains.py b/exercises/grains/grains.py index 194198fa681..5551148c11d 100644 --- a/exercises/grains/grains.py +++ b/exercises/grains/grains.py @@ -1,6 +1,11 @@ def square(number): - pass + if not 1 <= number <= 64: + raise ValueError("error range") + return pow(2, number - 1) def total(number): - pass + if not 1 <= number <= 64: + raise ValueError("error range") + return pow(2, number) - 1 + diff --git a/exercises/hamming/hamming.py b/exercises/hamming/hamming.py index 056fec41a1c..dc69006b7c3 100644 --- a/exercises/hamming/hamming.py +++ b/exercises/hamming/hamming.py @@ -1,2 +1,5 @@ def distance(strand_a, strand_b): - pass + if len(strand_a) != len(strand_b): + raise ValueError("a is not equal to b") + return sum(a != b for a, b in zip(strand_a, strand_b)) + diff --git a/exercises/hangman/hangman.py b/exercises/hangman/hangman.py index fe4e52ddb90..6c9f3a29b2d 100644 --- a/exercises/hangman/hangman.py +++ b/exercises/hangman/hangman.py @@ -1,3 +1,4 @@ +import re # Game status categories # Change the values as you see fit STATUS_WIN = "win" @@ -9,12 +10,28 @@ class Hangman(object): def __init__(self, word): self.remaining_guesses = 9 self.status = STATUS_ONGOING + self.word = word + self.mask_char = ['_'] * len(self.word) def guess(self, char): - pass + if self.status is not STATUS_ONGOING: + raise ValueError("Game end!") + + # char repeat or error + if self.word.find(char) != -1 and (char not in self.mask_char): + for a, b in enumerate(self.word): + if char == b: + self.mask_char[a] = char + else: + self.remaining_guesses -= 1 + + if self.remaining_guesses < 0: + self.status = STATUS_LOSE + if set(self.mask_char) == set(self.word): + self.status = STATUS_WIN def get_masked_word(self): - pass + return ''.join(self.mask_char) def get_status(self): - pass + return self.status diff --git a/exercises/prime-factors/prime_factors.py b/exercises/prime-factors/prime_factors.py index c3b672cfdf3..4c60b74c453 100644 --- a/exercises/prime-factors/prime_factors.py +++ b/exercises/prime-factors/prime_factors.py @@ -1,2 +1,32 @@ +# def factors(value): +# results = [] +# divisor = 2 +# count = 0 +# while divisor <= value: +# count += 1 +# if value % divisor == 0: +# results.append(divisor) +# value = value / divisor +# else: +# divisor += 1 +# print(count) +# return results +# + def factors(value): - pass + count = 0 + prime = 2 + prime_factors = [] + + while not value == 1: + count += 1 + if value % prime == 0: + value /= prime + prime_factors.append(prime) + else: + prime += 1 + print(count) + return prime_factors + + +factors(45) \ No newline at end of file diff --git a/exercises/protein-translation/protein_translation.py b/exercises/protein-translation/protein_translation.py index d3ce2ec2ff5..4e8911bdec4 100644 --- a/exercises/protein-translation/protein_translation.py +++ b/exercises/protein-translation/protein_translation.py @@ -1,2 +1,40 @@ +protein_dict = { + 'AUG': 'Methionine', + "UUU": 'Phenylalanine', + 'UUC': 'Phenylalanine', + 'UUA': 'Leucine', + 'UUG': 'Leucine', + 'UCU': 'Serine', + 'UCC': 'Serine', + 'UCA': 'Serine', + 'UCG': 'Serine', + 'UAU': 'Tyrosine', + 'UAC': 'Tyrosine', + 'UGU': 'Cysteine', + 'UGC': 'Cysteine', + 'UGG': 'Tryptophan', + 'UAA': 'STOP', + 'UAG': 'STOP', + 'UGA': 'STOP' +} + + +def identify(codon): + return protein_dict.get(codon, None) + + def proteins(strand): - pass + proteins_list = [] + codon_queue = [] + for i in strand: + codon_queue.append(i) + if len(codon_queue) > 3: + codon_queue.pop(0) + if len(codon_queue) == 3: + protein = identify(''.join(codon_queue)) + if protein and protein != 'STOP': + proteins_list.append(protein) + codon_queue.clear() + else: + break + return proteins_list diff --git a/exercises/raindrops/raindrops.py b/exercises/raindrops/raindrops.py index f38f3b611d4..b7947390e45 100644 --- a/exercises/raindrops/raindrops.py +++ b/exercises/raindrops/raindrops.py @@ -1,2 +1,7 @@ def convert(number): - pass + return ( + f"{ 'Pling' if number % 3 == 0 else ''}" + f"{ 'Plang' if number % 5 == 0 else ''}" + f"{ 'Plong' if number % 7 == 0 else ''}" + f"{ number if number % 3 != 0 and number % 5 != 0 and number % 7 != 0 else ''}" + ) diff --git a/exercises/rational-numbers/rational_numbers.py b/exercises/rational-numbers/rational_numbers.py index f94d20b4771..550d6f4bd6f 100644 --- a/exercises/rational-numbers/rational_numbers.py +++ b/exercises/rational-numbers/rational_numbers.py @@ -3,32 +3,50 @@ class Rational(object): def __init__(self, numer, denom): - self.numer = None - self.denom = None + if denom == 0: + raise ValueError('denom should not be 0') + i = 2 + while i <= abs(numer): + if numer % i == 0 and denom % i == 0: + numer = numer // i + denom = denom // i + else: + i += 1 + if numer * denom < 0: + self.numer = -abs(numer) + self.denom = abs(denom) + else: + self.numer = abs(numer) + self.denom = abs(denom) def __eq__(self, other): + if self.numer == 0 and other.numer == 0: + return True return self.numer == other.numer and self.denom == other.denom def __repr__(self): return '{}/{}'.format(self.numer, self.denom) def __add__(self, other): - pass + return Rational(self.numer * other.denom + other.numer * self.denom, self.denom * other.denom) def __sub__(self, other): - pass + return Rational(self.numer * other.denom - other.numer * self.denom, self.denom * other.denom) def __mul__(self, other): - pass + return Rational(self.numer * other.numer, self.denom * other.denom) def __truediv__(self, other): - pass + if self.denom * other.numer != 0: + return Rational(self.numer * other.denom, self.denom * other.numer) + else: + raise ValueError() def __abs__(self): - pass + return Rational(abs(self.numer), abs(self.denom)) def __pow__(self, power): - pass + return Rational(self.numer ** power, self.denom ** power) if power > 0 else Rational(self.denom ** -power, self.numer ** -power) def __rpow__(self, base): - pass + return base ** (self.numer / self.denom) diff --git a/exercises/resistor-color-duo/resistor_color_duo.py b/exercises/resistor-color-duo/resistor_color_duo.py index f83a1c237cb..b27aaef389a 100644 --- a/exercises/resistor-color-duo/resistor_color_duo.py +++ b/exercises/resistor-color-duo/resistor_color_duo.py @@ -1,2 +1,16 @@ +color_dict = { + 'black': 0, + 'brown': 1, + 'red': 2, + 'orange': 3, + 'yellow': 4, + 'green': 5, + 'blue': 6, + 'violet': 7, + 'grey': 8, + 'white': 9, +} + + def value(colors): - pass + return int(''.join(str(color_dict[i]) for i in colors[0: 2])) diff --git a/exercises/resistor-color/resistor_color.py b/exercises/resistor-color/resistor_color.py index 34915958e8d..4f72a30e23c 100644 --- a/exercises/resistor-color/resistor_color.py +++ b/exercises/resistor-color/resistor_color.py @@ -1,6 +1,20 @@ +color_dict = { + 'black': 0, + 'brown': 1, + 'red': 2, + 'orange': 3, + 'yellow': 4, + 'green': 5, + 'blue': 6, + 'violet': 7, + 'grey': 8, + 'white': 9, +} + + def color_code(color): - pass + return color_dict.get(color) def colors(): - pass + return list(color_dict.keys()) diff --git a/exercises/reverse-string/reverse_string.py b/exercises/reverse-string/reverse_string.py index 4690cc7c834..0f0a63f7339 100644 --- a/exercises/reverse-string/reverse_string.py +++ b/exercises/reverse-string/reverse_string.py @@ -1,2 +1,2 @@ def reverse(text): - pass + return text[::-1] diff --git a/exercises/rna-transcription/rna_transcription.py b/exercises/rna-transcription/rna_transcription.py index bb7be7795da..a7c7a633e3a 100644 --- a/exercises/rna-transcription/rna_transcription.py +++ b/exercises/rna-transcription/rna_transcription.py @@ -1,2 +1,6 @@ +from string import maketrans + + def to_rna(dna_strand): - pass + table = maketrans("GCTA", "CGAU") + return dna_strand.translate(table) diff --git a/exercises/sgf-parsing/sgf_parsing.py b/exercises/sgf-parsing/sgf_parsing.py index 6d2fef84e85..08bbd835d8d 100644 --- a/exercises/sgf-parsing/sgf_parsing.py +++ b/exercises/sgf-parsing/sgf_parsing.py @@ -25,5 +25,128 @@ def __ne__(self, other): return not self == other +def separate_root_children(input_string): + # Although this is the case in the test case, + # I must consider the situation that '\\;' and '\\(' + cursor = len(input_string) + parentheses_cursor = input_string.find("(;") + brackets_cursor = input_string.find("];") + if parentheses_cursor != -1: + # the node has many children + cursor = parentheses_cursor + elif brackets_cursor != -1: + # the node has a single child + cursor = brackets_cursor + 1 + + return input_string[:cursor], input_string[cursor:] + + +# analysis properties +def analysis(str, results={}): + try: + left_brackets_cursor = str.index('[') + right_brackets_cursor = str.index(']') + except ValueError: + # the node has not property + if str == '': + return + raise ValueError("Error format.") + + key = str[:left_brackets_cursor] + if not key.isupper(): + raise ValueError("Error format. Key should be capital letter.") + if not results.get(key, None): + results[key] = [] + + while True: + # if the right bracket is not a escape character, append to the list according to the key + # else should find the next right bracket + if str[right_brackets_cursor - 1:right_brackets_cursor] != '\\': + results[key].append(str[left_brackets_cursor + 1: right_brackets_cursor].replace('\\', '').replace("\t", ' ')) + # in the end + if (right_brackets_cursor + 1) == len(str): + return results + if str[right_brackets_cursor + 1] != '[': + return analysis(str[right_brackets_cursor + 1:], results) + else: + left_brackets_cursor = right_brackets_cursor + 1 + right_brackets_cursor = str.find(']', right_brackets_cursor + 1) + + +# for iteration +def _parse(input_string): + # analysis root node + if not (input_string.startswith("(;") and input_string.endswith(")")): + raise ValueError("Error format") + root_str, children_str = separate_root_children(input_string[1:-1]) + + properties = analysis(root_str[1:], results={}) + + children = [] + # if it has many child + if children_str.startswith('(') and children_str.endswith(")"): + left_cursor = children_str.find("(;") + right_cursor = children_str.find(")") + while True: + if children_str[right_cursor - 1: right_cursor] != '\\': + children.append(_parse(children_str[left_cursor:right_cursor + 1])) + if right_cursor + 1 == len(children_str): + break + if children_str[right_cursor + 1] != "(": + raise ValueError("Error format.") + left_cursor = right_cursor + 1 + right_cursor = children_str.find(")", right_cursor + 1) + # recognize the single child as a node(a SgfTree) and parse it + elif children_str.startswith(";"): + children.append(_parse("(" + children_str + ")")) + return properties, children + + +def transform_SgfTree(properties_dict, children_list): + if children_list: + children = [] + for i in children_list: + children.append(transform_SgfTree(i[0], i[1])) + return SgfTree(properties=properties_dict, children=children) + else: + return SgfTree(properties=properties_dict) + + def parse(input_string): - pass + properties, children = _parse(input_string) + return transform_SgfTree(properties, children) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/exercises/space-age/space_age.py b/exercises/space-age/space_age.py index c9de4aa9bf5..c649ef37773 100644 --- a/exercises/space-age/space_age.py +++ b/exercises/space-age/space_age.py @@ -1,3 +1,30 @@ class SpaceAge(object): + earth_year = 31557600.00 + def __init__(self, seconds): - pass + self.seconds = seconds + + def on_earth(self): + return round(self.seconds / self.earth_year, 2) + + def on_mercury(self): + return round(self.seconds / (self.earth_year * 0.2408467), 2) + + def on_venus(self): + return round(self.seconds / (self.earth_year * 0.61519726), 2) + + def on_mars(self): + return round(self.seconds / (self.earth_year * 1.8808158), 2) + + def on_jupiter(self): + return round(self.seconds / (self.earth_year * 11.862615), 2) + + def on_saturn(self): + return round(self.seconds / (self.earth_year * 29.447498), 2) + + def on_uranus(self): + return round(self.seconds / (self.earth_year * 84.016846), 2) + + def on_neptune(self): + return round(self.seconds / (self.earth_year * 164.79132), 2) + diff --git a/exercises/two-fer/two_fer.py b/exercises/two-fer/two_fer.py index 680c26b277a..55854ccbf39 100644 --- a/exercises/two-fer/two_fer.py +++ b/exercises/two-fer/two_fer.py @@ -1,2 +1,3 @@ -def two_fer(name): - pass +def two_fer(name='you'): + return f"One for {name}, one for me." + diff --git a/exercises/yacht/yacht.py b/exercises/yacht/yacht.py index bcf99719ecf..13a17a4e8e5 100644 --- a/exercises/yacht/yacht.py +++ b/exercises/yacht/yacht.py @@ -1,32 +1,43 @@ -""" -This exercise stub and the test suite contain several enumerated constants. - -Since Python 2 does not have the enum module, the idiomatic way to write -enumerated constants has traditionally been a NAME assigned to an arbitrary, -but unique value. An integer is traditionally used because it’s memory -efficient. -It is a common practice to export both constants and functions that work with -those constants (ex. the constants in the os, subprocess and re modules). - -You can learn more here: https://en.wikipedia.org/wiki/Enumerated_type -""" # Score categories. # Change the values as you see fit. -YACHT = None -ONES = None -TWOS = None -THREES = None -FOURS = None -FIVES = None -SIXES = None -FULL_HOUSE = None -FOUR_OF_A_KIND = None -LITTLE_STRAIGHT = None -BIG_STRAIGHT = None -CHOICE = None +YACHT = 0 +ONES = 1 +TWOS = 2 +THREES = 3 +FOURS = 4 +FIVES = 5 +SIXES = 6 +FULL_HOUSE = 7 +FOUR_OF_A_KIND = 8 +LITTLE_STRAIGHT = 9 +BIG_STRAIGHT = 10 +CHOICE = 11 def score(dice, category): - pass + if category == YACHT: + return 50 if len(set(dice)) == 1 else 0 + + if ONES <= category <= SIXES: + return category * dice.count(category) + + if category == FULL_HOUSE: + return sum(dice) if len(set(dice)) == 2 and dice.count(dice[0]) in (2, 3) else 0 + + if category == FOUR_OF_A_KIND: + for i in dice: + if dice.count(i) >= 4: + return i * 4 + return 0 + + if category == LITTLE_STRAIGHT: + return 30 if sorted(dice) == [1, 2, 3, 4, 5] else 0 + + if category == BIG_STRAIGHT: + return 30 if sorted(dice) == [2, 3, 4, 5, 6] else 0 + + if category == CHOICE: + return sum(dice) +