def test_normal(self): result = get_score('547/23XX-3X81453-') self.assertEqual(result, 113) with self.assertRaises(ValueError): get_score('547/23XX-3X81453') with self.assertRaises(ValueError): get_score('547/23XX-3X81453-5')
def test_incorrect_symbol_first_roll(self): with self.assertRaises(ValueError) as cm: bowling.get_score('aХ4/34-4') exc = cm.exception self.assertEqual( 'Некорректный символ в последовательности. Фрейм 1. Бросок 1. Полученный символ: a', exc.args[0])
def treatment(input_file, output_file): input_file = open(input_file, 'r', encoding='utf8') output_file = open(output_file, 'a', encoding='utf8') for line in input_file: if '### Tour' in line: score = {} print('\n', line, file=output_file) elif len(line) > 20: name, res = line.split('\t') name = str(name) res = str(res) try: score[name] = get_score(result=res) print(name, res, 'Результат:', get_score(result=res), file=output_file) except Exception as exc: print(name, res, 'Результат:', exc, file=output_file) elif 'winner is .........' in line: try: for key in sorted(score.items(), key=lambda para: (para[1], para[0]), reverse=False): print(key) print(line[:-10], key[0], file=output_file) except ValueError: print('Победителя нет', file=output_file) input_file.close()
def test_scoring(self): result = bowling.get_score('Х4/34-4------------') # TODO везде говорится, что эначение для проверки передаётся первым параметром, аожидаемый результат - вторым. # Но если посмотреть результат теста, то будет видно, # что значение Expected берётся из первого параметра, а Actual - из второго. # Исходя из этого я и писал остальные тесты self.assertEqual(46, result, 'Некорректный подсчёт очков по старым правилам') result = bowling.get_score('Х4/34-4------------', new_rules=True) self.assertEqual(44, result, 'Некорректный подсчёт очков по новым правилам')
def test_incorrect_symbol_second_roll(self): with self.assertRaises(ValueError) as cm: bowling.get_score('Х4X') exc = cm.exception self.assertEqual( 'Некорректный символ в последовательности. Фрейм 2. Бросок 2. Полученный символ: X', exc.args[0]) with self.assertRaises(ValueError) as cm: bowling.get_score('Х55') exc = cm.exception self.assertEqual( 'За фрейм сбито 10 кеглей, но результат записан не как спейр, а как два числа. ' 'Фрейм 2. Количество кеглей за этот фрейм: 5 + 5 = 10', exc.args[0])
def act(self): with open(self.input_file, 'r', encoding='utf-8') as in_file,\ open(self.output_file, 'w', encoding='utf-8') as out_file: for line in in_file: format_line = line.split('\t') if len(format_line) == 2: try: person_result = get_score( format_line[1][:-1], calculation_method=self.version) if person_result: self.tour[format_line[0]] = person_result out_file.write( f"{format_line[0]}\t{format_line[1][:-1]:20}\t{str(person_result):<}\n" ) except (WrongFirstSymbol, InvalidNumberOfCharacters, InvalidNumberOfScore) as ex: out_file.write( f"{format_line[0]}\t{format_line[1][:-1]:20}\t{ex}\n" ) elif len(format_line) == 1: if "winner" in line: tour_winner = self.tour_winners() out_file.write( f"winner is {', '.join(list(tour_winner))}\n") else: out_file.write(line)
def writing(self): result_file = open(self.result_file, mode='a+', encoding='utf-8') with open(self.initial_file, mode='r', encoding='utf-8') as file: for line in file: line = line.strip('\n') try: if '\t' in line: line = line.split('\t') name = line[0] scope = line[1] digit_scope = get_score(scope, state=self.state) new_line = f'{name}\t{scope}\t{digit_scope}' result_file.write(f'{new_line}\n') self.winner_info(name, digit_scope) self.count_game(name) elif 'winner is' in line: winner_line = f'winner is {self.winner[0]}' result_file.write(f'{winner_line}\n') self.count_win(self.winner[0]) self.winner.clear() else: result_file.write(f'{line}\n') except ValueError as exc: new_line = f'{name}\t{scope}\t{exc.args}' result_file.write(f'{new_line}\n') except IndexError: new_line = f'{name}\t{scope}\t(Не верное кол-во фреймов.)' result_file.write(f'{new_line}\n') result_file.close()
def _get_scores(self): """ Считает очки игроков в этом туре. Собирает словарь вида {имя_игрока: набранные_очки}. Если была ошибка парсинга, то ошибка откладывается в отдельный словарь вида {имя_игрока: текст_ошибки}, а в словарь очков добавляется запись {имя_игрока: -1} """ for line in self.tour_results[1:-1]: name, game_result = line.split() try: score = get_score(game_result) except Exception as exc: self._scores[name] = -1 self.errors[name] = 'Error: ' + str(exc) else: self._scores[name] = score
def to_parce_doc(path, choosen_market): path_normalized = os.path.normpath(path) with open(path_normalized, "r") as txt: winner_name = '-' winner_score = 0 separator = ' ' for line in txt: line_for_yield = line.rstrip() line_tmp = line_for_yield.split() if 'Tour' in line_tmp: yield line continue if 'winner' in line_tmp: line_tmp.pop(-1) line_tmp.append(winner_name) line_tmp = separator.join(line_tmp) line_tmp = line_tmp + '\n' + '\n' yield line_tmp winner_score = 0 winner_name = '-' continue if len(line_tmp) == 2: gamer_name = line_tmp[0] gamer_result = line_tmp[1] try: quantity_of_score = get_score(game_result=gamer_result, status=choosen_market) except Exception as exc: quantity_of_score = 0 line = line_for_yield + f' {exc}\n' yield line continue line = line_for_yield + f' {quantity_of_score}\n' yield line if quantity_of_score > winner_score: winner_name = copy.copy(gamer_name) winner_score = copy.copy(quantity_of_score) return
def score_tournament(in_file, out_file): with open(os.path.join(in_file), encoding='utf8') as file_in: for line in file_in: if line.startswith('###') or len(line) == 1: info_to_out.append(line[:-1]) elif line.startswith('winner'): info_to_out.append(f'Winner is {winner_in_tour[max(winner_in_tour)]}') winner_in_tour.clear() else: line = line.split() try: get_score_name = bowling.get_score(get_string=line[1]) except (Exception, bowling.SumError, bowling.WrongSymbol) as exc: winner_in_tour[0] = line[0] info_to_out.append(f'{line[0]} {line[1]} 0 => {exc}') else: winner_in_tour[get_score_name] = line[0] info_to_out.append(f'{line[0]} {line[1]} {get_score_name}') with open(os.path.join(out_file), mode='a', encoding='utf-8') as file_out: for line in info_to_out: file_out.write(line + '\n')
def get_score_from_to(input_file, output_file, count_type): substring1 = '###' substring2 = 'winner is ' # with open(input_file, 'r', encoding='utf-8') as file, open(output_file, 'w') as writefile: with open(input_file, 'r') as file, open(output_file, 'w') as writefile: for line in file: try: if substring1 in line: max_number = 0 writefile.write(line) elif substring2 in line: writefile.write(substring2 + '' + winner_name + '\n') else: name, result = line.split(' ') result = result.strip() count = get_score(result, count_type) writefile.write(line.strip() + ' ' + str(count) + '\n') if count > max_number: max_number = count winner_name = name except Exception as exc: print('error', exc, line)
def test_incorrect_sequence_length(self): with self.assertRaises(bowling.FrameCountError): bowling.get_score('X' * 9) with self.assertRaises(bowling.FrameCountError): bowling.get_score('Х' * 11)
def test_normal_game(self): self.assertEqual(get_score('Х4/34-452Х-/729---', international=False), 106)
def test_short_game_international(self): self.assertEqual(get_score('ХXX347/21'), 92)
# Например, для игры из 4 фреймов запись результатов может выглядеть так: # «Х4/34-4» # Предлагается упрощенный способ подсчета количества очков: # «Х» – strike всегда 20 очков # «4/» - spare всегда 15 очков # «34» – сумма 3+4=7 # «-4» - сумма 0+4=4 # То есть для игры «Х4/34-4» сумма очков равна 20+15+7+4=46 # # Надо написать python-модуль (назвать bowling), предоставляющий API расчета количества очков: # функцию get_score, принимающую параметр game_result. Функция должна выбрасывать исключения, # когда game_result содержит некорректные данные. Использовать стандартные исключения по максимуму, # если не хватает - создать свои. # # Обязательно написать тесты на этот модуль. Расположить в папке tests. # Из текущего файла сделать консольную утилиту для определения количества очков, с помощью пакета argparse # Скрипт должен принимать параметр --result и печатать на консоль: # Количество очков для результатов ХХХ - УУУ. import argparse from bowling import get_score parser = argparse.ArgumentParser( description='подсчет колличества очков по строке с результатом') parser.add_argument("--a", "--argument", help='строка с результатом игры') args = parser.parse_args() result = args.a print('Количество очков для результатов', result, '-', get_score(game_result=result))
# Если во фрейме сбит спэр, то сумма очков будет равна количеству сбитых кеглей в этом фрейме (10 кеглей) # плюс количество фактически сбитых кеглей за первый бросок шара в следующем фрейме. # # Если фрейм остался открытым, то сумма очков будет равна количеству сбитых кеглей в этом фрейме. # # Страйк и спэр в последнем фрейме - по 10 очков. # # То есть для игры «Х4/34» сумма очков равна 10+10 + 10+3 + 3+4 = 40, # а для игры «ХXX347/21» - 10+20 + 10+13 + 10+7 + 3+4 + 10+2 + 3 = 92 # Необходимые изменения сделать во всех модулях. Тесты - дополнить. # "И да, старые правила должны остаться! для внутреннего рынка..." - уточнил менеджер напоследок. import argparse from bowling import get_score parser = argparse.ArgumentParser( description='подсчет колличества очков по строке с результатом') parser.add_argument("--a", "--argument", help='строка с результатом игры') parser.add_argument("--s", "--state", help='market для внешнего рынка/self для внутреннего') args = parser.parse_args() result = args.a state = args.s print('Количество очков для результатов', result, '-', get_score(game_result=result, state=state)) # зачет!
# -*- coding: utf-8 -*- import bowling as b import argparse parser = argparse.ArgumentParser() parser.add_argument('--result', dest='game_result', help='Game data') args = parser.parse_args() try: res = b.get_score(args.game_result) except ValueError as exp: print(exp) else: print(f'In game {args.game_result} scores {res}')
def test_all_strikes(self): self.score = get_score(result='XXXXXXXXXX') self.assertEqual(200, self.score)
def test_normal_game_international(self): self.assertEqual(get_score('ХXX347/21XXX5/'), 177)
def test_short_game(self): self.assertEqual(get_score('Х4/34-4', international=False), 46)
def test_get_score_function_good_result(game_result, score): res = get_score(game_result=game_result) assert res == approx(expected=score)
(f'Результат игры – строка с записью результатов фреймов. ' f'Символов-разделителей между фреймами нет.{nbsp * 12} ' f'Результаты фрейма записываются символами:{nbsp * 12} ' f'{nbsp * 2}Х – strike, все 10 кеглей сбиты первым броском;{nbsp * 5} ' f'{nbsp * 2}<число>/ - spare, в первый бросок сбиты 4 кегли,{nbsp * 4} ' f'{nbsp * 20}во второй – остальные;{nbsp * 12} ' f'{nbsp * 2}<число><число> – в первый бросок сбито 3,{nbsp * 11} ' f'{nbsp * 20}во второй – 4 кегли;{nbsp * 14} ' f'{nbsp * 2}- - прочерк, ни одной кегли не было сбито{nbsp * 11} ' f'{nbsp * 20}за первый бросок')) parser.add_argument( '-new_rules', action='store_const', const=True, dest='new_rules', default=False, help='Флаг включает подсчёт очков игры по новым правилам') args = parser.parse_args() try: result = get_score(args.game_result, args.new_rules) except Exception as exc: print(exc) exit() print(f'Количество очков для результатов {args.game_result} - {result}') # При написании кода помнить, что заказчик может захотеть доработок и новых возможностей... # И, возможно, вам пригодится паттерн проектирования "Состояние", # см https://clck.ru/Fudd8 и https://refactoring.guru/ru/design-patterns/state # Зачет!
def command_line(): parser = argparse.ArgumentParser(description='Подсчет очков в боулинге') parser.add_argument('result', type=str, help='Результат') args = parser.parse_args() get_score(args.result)
def test_incomplete_last_frame(self): with self.assertRaises(IndexError) as cm: bowling.get_score('Х4') exc = cm.exception self.assertEqual('Последний фрейм не завершён - нет второго броска', exc.args[0])
# вместо <число> может стоять прочерк «-», например «-4» - ни одной кегли не было сбито за первый бросок # Результат игры – строка с записью результатов фреймов. Символов-разделителей между фреймами нет. # Например, для игры из 4 фреймов запись результатов может выглядеть так: # «Х4/34-4» # Предлагается упрощенный способ подсчета количества очков: # «Х» – strike всегда 20 очков # «4/» - spare всегда 15 очков # «34» – сумма 3+4=7 # «-4» - сумма 0+4=4 # То есть для игры «Х4/34-4» сумма очков равна 20+15+7+4=46 # # Надо написать python-модуль (назвать bowling), предоставляющий API расчета количества очков: # функцию get_score, принимающую параметр game_result. Функция должна выбрасывать исключения, # когда game_result содержит некорректные данные. Использовать стандартные исключения по максимуму, # если не хватает - создать свои. # # Обязательно написать тесты на этот модуль. Расположить в папке tests. # Из текущего файла сделать консольную утилиту для определения количества очков, с помощью пакета argparse # Скрипт должен принимать параметр --result и печатать на консоль: # Количество очков для результатов ХХХ - УУУ. import argparse import bowling parser = argparse.ArgumentParser( description='Запуск из командной строки: python файл данные') parser.add_argument('game_result', type=str, help='Результаты игры') args = parser.parse_args() bowling.get_score(args.game_result) #зачёт!
from bowling import get_score import bowling as bowling # from bowling_V1 import get_score # import bowling_V1 as bowling if __name__ == '__main__': game_score = get_score('X4/34', international=True) game_score = get_score('XXX347/21', international=True) game_score = get_score('X4/34', international=False) game_score = get_score('XXX347/21', international=False) game_score = get_score('XXX347/21XXX5/') game_score = get_score('X4/34-4') game_score = get_score('15-/X1/42') game_score = get_score('X4/34-452X-/729-1-') game_score = get_score('XXXXXXXXX') try: game_score = get_score('141/FA457X') except bowling.BadStringError as exc: print(exc) try: game_score = get_score('XXXXXXXXX111') except bowling.FrameCountError as exc: print(exc) try: game_score = get_score('1XXXXXXXXXX') except bowling.StrikeError as exc:
# Надо написать python-модуль (назвать bowling), предоставляющий API расчета количества очков: # функцию get_score, принимающую параметр game_result. Функция должна выбрасывать исключения, # когда game_result содержит некорректные данные. Использовать стандартные исключения по максимуму, # если не хватает - создать свои. # # Обязательно написать тесты на этот модуль. Расположить в папке tests. # Из текущего файла сделать консольную утилиту для определения количества очков, с помощью пакета argparse # Скрипт должен принимать параметр --result и печатать на консоль: # Количество очков для результатов ХХХ - УУУ. # При написании кода помнить, что заказчик может захотеть доработок и новых возможностей... # И, возможно, вам пригодится паттерн проектирования "Состояние", # см https://clck.ru/Fudd8 и https://refactoring.guru/ru/design-patterns/state import argparse from bowling import get_score parser = argparse.ArgumentParser(description='Bowling score parser') parser.add_argument('--result', type=str, default=None) args = parser.parse_args() result = args.result if result is None: result = 'Х4/34-48/45173/X18' else: result = args.result get_score(result=result) #зачет!
def test_no_second_throw_after_strike(self): with self.assertRaisesRegex( Exception, 'Введено неправильное значение после strike'): get_score('3532X333/2/62--62X1')
def execute(self) -> None: self.score = get_score(game_result=self.game_result) print( f"Количество очков для результатов {self.game_result} => {self.score}" )
def test_incorrect_frames(self): with self.assertRaisesRegex(Exception, 'Не правильное количество фреймов!'): get_score('1744XX23--4/')