Coverage for src\aoc2022\days\day10.py: 100%

44 statements  

« prev     ^ index     » next       coverage.py v7.0.0, created at 2022-12-23 05:19 +0000

1from typing import Generator, List, Tuple 

2 

3from src.aoc2022 import utils 

4 

5 

6def parse_data_to_array(raw_data: str) -> List[List[str]]: 

7 """ 

8 Parse the raw data into a 1D list of instruction sets 

9 

10 :param raw_data: Raw data containing numerical data 

11 :type raw_data: str 

12 

13 :return: parsed matrix of values 

14 :rtype: List[List[str]] 

15 """ 

16 parsed_list = [] 

17 for line in raw_data.split("\n"): 

18 instructions = line.split(" ") 

19 parsed_list.append(instructions) 

20 

21 return parsed_list 

22 

23 

24def simulate_cpu_state_machine( 

25 instructions: List[List[str]], 

26) -> Generator[Tuple[int, int], None, None]: 

27 """ 

28 Creates a generator that simulates the CPU on a per-cycle basis 

29 

30 :param instructions: List of instructions to execute 

31 :type instructions: List[List[str]] 

32 

33 :return: per-cycle CPU simulator 

34 :rtype: Generator[Tuple[int, int], None, None] 

35 """ 

36 register_value = 1 

37 cycle = 0 

38 

39 for instruction_set in instructions: 

40 match instruction_set: # noqa 

41 case ["noop"]: # noqa: E211 

42 cycle += 1 

43 yield (cycle, register_value) 

44 case ["addx", num]: # noqa: E211 

45 value = int(num) # noqa: F821 

46 cycle += 1 

47 yield (cycle, register_value) 

48 cycle += 1 

49 yield (cycle, register_value) 

50 register_value += value 

51 case _: # noqa: E211 

52 raise ValueError(f"Invalid CPU instruction {instruction_set}") 

53 

54 

55def get_total_signal_strength(instructions: List[List[str]]) -> int: 

56 """ 

57 Computes the total signal strength as sum of cycle * register value for 

58 n = 20, 60, 100, 140... 

59 

60 :param instructions: List of instructions to execute 

61 :type instructions: List[List[str]] 

62 

63 :return: total signal strength 

64 :rtype: int 

65 """ 

66 running_sum = 0 

67 cpu_simulator = simulate_cpu_state_machine(instructions) 

68 

69 for cycle_number, register_value in cpu_simulator: 

70 if (cycle_number - 20) % 40 == 0: 

71 running_sum += cycle_number * register_value 

72 

73 return running_sum 

74 

75 

76def render_cpu_pixel_values(instructions: List[List[str]]) -> str: 

77 """ 

78 Render the signal to a simulated console 

79 

80 :param instructions: List of instructions to execute 

81 :type instructions: List[List[str]] 

82 

83 :return: rendered console output 

84 :rtype: str 

85 """ 

86 cpu_simulator = simulate_cpu_state_machine(instructions) 

87 

88 line_width = 40 

89 render_chars = [] 

90 for cycle_number, register_value in cpu_simulator: 

91 cursor_pos = (cycle_number - 1) % line_width 

92 

93 if cursor_pos == 0: 

94 render_chars.append("\n") 

95 

96 if abs(register_value - cursor_pos) <= 1: 

97 render_chars.append("#") 

98 else: 

99 render_chars.append(".") 

100 

101 return "".join(render_chars[1:]) # remove leading newline 

102 

103 

104if __name__ == "__main__": # pragma: no cover 

105 

106 raw_data = utils.get_raw_data("./src/aoc2022/data/day10.txt") 

107 

108 parsed_data = parse_data_to_array(raw_data) 

109 

110 res = get_total_signal_strength(parsed_data) 

111 

112 print(f"The total signal strength is {res}") 

113 

114 rendered_console = render_cpu_pixel_values(parsed_data) 

115 

116 print(f"The rendered console is :\n{rendered_console}")