diff --git a/Brainfuck/__main__.py b/Brainfuck/__main__.py index d8d7d66..ac3d155 100644 --- a/Brainfuck/__main__.py +++ b/Brainfuck/__main__.py @@ -19,6 +19,7 @@ if __name__ == "__main__": # Parse the file argument file_parser = ArgumentParser("NanoBASIC") - file_parser.add_argument("brainfuck_file", help="A text file containing Brainfuck source code.") + file_parser.add_argument("brainfuck_file", + help="A file containing Brainfuck source code.") arguments = file_parser.parse_args() Brainfuck(arguments.brainfuck_file).execute() diff --git a/Brainfuck/brainfuck.py b/Brainfuck/brainfuck.py index ebeb602..43179e9 100644 --- a/Brainfuck/brainfuck.py +++ b/Brainfuck/brainfuck.py @@ -48,7 +48,7 @@ def execute(self): instruction_index = self.find_bracket_match(instruction_index, False) instruction_index += 1 - # Find the location of the corresponding matching bracket to the one at *start* + # Find the location of the corresponding bracket to the one at *start* # If *forward* is true go to the right looking for a matching "]" # Otherwise do the reverse def find_bracket_match(self, start: int, forward: bool) -> int: @@ -66,7 +66,7 @@ def find_bracket_match(self, start: int, forward: bool) -> int: in_between_brackets += 1 location += direction # Didn't find a match - print(f"Error: could not find matching bracket for {start_bracket} at {start}.") + print(f"Error: could not find match for {start_bracket} at {start}.") return start diff --git a/Chip8/__main__.py b/Chip8/__main__.py index babf926..8f8ee0c 100644 --- a/Chip8/__main__.py +++ b/Chip8/__main__.py @@ -25,9 +25,11 @@ def run(program_data: bytes, name: str): # Startup Pygame, create the window, and load the sound pygame.init() - screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SCALED) + screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), + pygame.SCALED) pygame.display.set_caption(f"Chip8 - {os.path.basename(name)}") - bee_sound = pygame.mixer.Sound(os.path.dirname(os.path.realpath(__file__)) + "/bee.wav") + bee_sound = pygame.mixer.Sound(os.path.dirname(os.path.realpath(__file__)) + + "/bee.wav") currently_playing_sound = False vm = VM(program_data) # Load the virtual machine with the program data timer_accumulator = 0.0 # Used to limit the timer to 60 Hz @@ -63,7 +65,7 @@ def run(program_data: bytes, name: str): # Handle timing frame_end = timer() - frame_time = frame_end - frame_start # time it took for this iteration in seconds + frame_time = frame_end - frame_start # time it took in seconds timer_accumulator += frame_time # Every 1/60 of a second decrement the timers if timer_accumulator > TIMER_DELAY: @@ -79,7 +81,8 @@ def run(program_data: bytes, name: str): if __name__ == "__main__": # Parse the file argument file_parser = ArgumentParser("Chip8") - file_parser.add_argument("rom_file", help="A file containing a Chip-8 game.") + file_parser.add_argument("rom_file", + help="A file containing a Chip-8 game.") arguments = file_parser.parse_args() with open(arguments.rom_file, "rb") as fp: file_data = fp.read() diff --git a/Chip8/vm.py b/Chip8/vm.py index ac4292e..7efbc5f 100644 --- a/Chip8/vm.py +++ b/Chip8/vm.py @@ -81,7 +81,8 @@ def __init__(self, program_data: bytes): # ours can just be unlimited and expand/contract as needed self.stack = [] # Graphics buffer for the screen - 64 x 32 pixels - self.display_buffer = np.zeros((SCREEN_WIDTH, SCREEN_HEIGHT), dtype=np.uint32) + self.display_buffer = np.zeros((SCREEN_WIDTH, SCREEN_HEIGHT), + dtype=np.uint32) self.needs_redraw = False # Timers - really simple registers that count down to 0 at 60 hertz self.delay_timer = 0 @@ -100,9 +101,9 @@ def decrement_timers(self): def play_sound(self) -> bool: return self.sound_timer > 0 - # Draw a sprite at *x*, *y* using data at *i* and with a height of *height* + # Draw a sprite at *x*, *y* using data at *i* with a height of *height* def draw_sprite(self, x: int, y: int, height: int): - flipped_black = False # did drawing this flip any pixels from white to black? + flipped_black = False # did drawing this flip any pixels? for row in range(0, height): row_bits = self.ram[self.i + row] for col in range(0, SPRITE_WIDTH): @@ -112,11 +113,13 @@ def draw_sprite(self, x: int, y: int, height: int): continue # Ignore off-screen pixels new_bit = (row_bits >> (7 - col)) & 1 old_bit = self.display_buffer[px, py] & 1 - if new_bit & old_bit: # If both are set, they will get flipped white -> black + if new_bit & old_bit: # If both set, flip white -> black flipped_black = True - new_pixel = new_bit ^ old_bit # Chip 8 draws by XORing, which flips everything + # Chip 8 draws by XORing, which flips everything + new_pixel = new_bit ^ old_bit self.display_buffer[px, py] = WHITE if new_pixel else BLACK - self.v[0xF] = 1 if flipped_black else 0 # set flipped flag for collision detection + # set flipped flag for collision detection + self.v[0xF] = 1 if flipped_black else 0 def step(self): # we look at the opcode in terms of its nibbles (4 bit pieces) @@ -139,7 +142,7 @@ def step(self): self.pc = self.stack.pop() jumped = True case (0x0, n1, n2, n3): # call program - self.pc = concat_nibbles(n1, n2, n3) # go to program start + self.pc = concat_nibbles(n1, n2, n3) # go to start # clear registers self.delay_timer = 0 self.sound_timer = 0 @@ -153,7 +156,7 @@ def step(self): self.pc = concat_nibbles(n1, n2, n3) jumped = True case (0x2, n1, n2, n3): # call subroutine - self.stack.append(self.pc + 2) # return location onto the stack + self.stack.append(self.pc + 2) # put return place on stack self.pc = concat_nibbles(n1, n2, n3) # goto subroutine jumped = True case (0x3, x, _, _): # conditional skip v[x] equal last2 @@ -261,7 +264,8 @@ def step(self): for r in range(0, x + 1): self.v[r] = self.ram[self.i + r] case _: - print(f"Unknown opcode {(hex(first), hex(second), hex(third), hex(fourth))}!") + print(f"Unknown opcode {(hex(first), hex(second), + hex(third), hex(fourth))}!") if not jumped: self.pc += 2 # increment program counter diff --git a/Impressionist/__main__.py b/Impressionist/__main__.py index ecb3795..a555891 100644 --- a/Impressionist/__main__.py +++ b/Impressionist/__main__.py @@ -19,16 +19,16 @@ if __name__ == "__main__": # Parse the file argument argument_parser = ArgumentParser("Impressionist") - argument_parser.add_argument("image_file", help="The input image to be painted.") - argument_parser.add_argument("output_file", help="The final resulting abstract art image.") + argument_parser.add_argument("image_file", help="The input image") + argument_parser.add_argument("output_file", help="The resulting abstract art") argument_parser.add_argument('-t', '--trials', type=int, default=10000, help='The number of trials to run (default 10000).') - argument_parser.add_argument('-m', '--method', choices=['random', 'average', 'common'], - default='average', + argument_parser.add_argument('-m', '--method', + choices=['random', 'average', 'common'], default='average', help='Shape color determination method (default average).') argument_parser.add_argument('-s', '--shape', choices=['ellipse', 'triangle', - 'quadrilateral', 'line'], default='ellipse', - help='The shape type to use (default ellipse).') + 'quadrilateral', 'line'], + default='ellipse', help='The shape type (default ellipse).') argument_parser.add_argument('-l', '--length', type=int, default=256, help='The length of the final image in pixels (default 256).') argument_parser.add_argument('-v', '--vector', default=False, action='store_true', diff --git a/Impressionist/impressionist.py b/Impressionist/impressionist.py index c42d5e1..320217f 100644 --- a/Impressionist/impressionist.py +++ b/Impressionist/impressionist.py @@ -125,7 +125,7 @@ def experiment() -> bool: return False if experiment(): - # Try expanding every direction, keep expanding in any directions that are better + # Try expanding every direction, keep going in better directions for index in range(len(coordinates)): for amount in (-1, 1): while True: diff --git a/Impressionist/svg.py b/Impressionist/svg.py index 43395ec..28b140a 100644 --- a/Impressionist/svg.py +++ b/Impressionist/svg.py @@ -23,7 +23,8 @@ def __init__(self, width: int, height: int, background_color: tuple[int, int, in def draw_ellipse(self, x1: int, y1: int, x2: int, y2: int, color: tuple[int, int, int]): self.content += f'\n' + (f'rx="{abs(x1 - x2) // 2}" ry="{abs(y1 - y2) // 2}' + f'" fill="rgb{color}" />\n') def draw_line(self, x1: int, y1: int, x2: int, y2: int, color: tuple[int, int, int]): self.content += f' Self: height=float(data[5]), width=float(data[6])) def distance(self, other: Self) -> float: - return ((self.length1 - other.length1) ** 2 + (self.length2 - other.length2) ** 2 + - (self.length3 - other.length3) ** 2 + (self.height - other.height) ** 2 + + return ((self.length1 - other.length1) ** 2 + + (self.length2 - other.length2) ** 2 + + (self.length3 - other.length3) ** 2 + + (self.height - other.height) ** 2 + (self.width - other.width) ** 2) ** 0.5 diff --git a/KNN/knn.py b/KNN/knn.py index 9c1e440..7f6547a 100644 --- a/KNN/knn.py +++ b/KNN/knn.py @@ -29,7 +29,8 @@ def distance(self, other: Self) -> float: ... class KNN[DP: DataPoint]: - def __init__(self, data_point_type: type[DP], file_path: str, has_header: bool = True) -> None: + def __init__(self, data_point_type: type[DP], file_path: str, + has_header: bool = True) -> None: self.data_point_type = data_point_type self.data_points = [] self._read_csv(file_path, has_header) @@ -41,9 +42,10 @@ def _read_csv(self, file_path: str, has_header: bool) -> None: if has_header: _ = next(reader) for row in reader: - self.data_points.append(self.data_point_type.from_string_data(row)) + self.data_points.append( + self.data_point_type.from_string_data(row)) - # Find the k nearest neighbors of a given data point based on the distance method + # Find the k nearest neighbors of a given data point def nearest(self, k: int, data_point: DP) -> list[DP]: return sorted(self.data_points, key=data_point.distance)[:k] @@ -57,10 +59,12 @@ def classify(self, k: int, data_point: DP) -> str: # Find the average of that property from the neighbors and return it def predict(self, k: int, data_point: DP, property_name: str) -> float: neighbors = self.nearest(k, data_point) - return sum([getattr(neighbor, property_name) for neighbor in neighbors]) / len(neighbors) + return (sum([getattr(neighbor, property_name) for neighbor in neighbors]) + / len(neighbors)) # Predict a NumPy array property of a data point based on the k nearest neighbors # Find the average of that property from the neighbors and return it def predict_array(self, k: int, data_point: DP, property_name: str) -> np.ndarray: neighbors = self.nearest(k, data_point) - return np.sum([getattr(neighbor, property_name) for neighbor in neighbors], axis=0) / len(neighbors) + return (np.sum([getattr(neighbor, property_name) for neighbor in neighbors], axis=0) + / len(neighbors)) diff --git a/NESEmulator/__main__.py b/NESEmulator/__main__.py index 64ac698..cbedf90 100644 --- a/NESEmulator/__main__.py +++ b/NESEmulator/__main__.py @@ -93,7 +93,8 @@ def run(rom: ROM, name: str): if __name__ == "__main__": # Parse the file argument file_parser = ArgumentParser("NESEmulator") - file_parser.add_argument("rom_file", help="A file containing an NES game in iNES format.") + file_parser.add_argument("rom_file", + help="An NES game file in iNES format.") arguments = file_parser.parse_args() game = ROM(arguments.rom_file) run(game, arguments.rom_file) diff --git a/NESEmulator/cpu.py b/NESEmulator/cpu.py index e10e11c..babede5 100644 --- a/NESEmulator/cpu.py +++ b/NESEmulator/cpu.py @@ -21,16 +21,20 @@ from NESEmulator.ppu import PPU, SPR_RAM_SIZE from NESEmulator.rom import ROM -MemMode = Enum("MemMode", "DUMMY ABSOLUTE ABSOLUTE_X ABSOLUTE_Y ACCUMULATOR IMMEDIATE " - "IMPLIED INDEXED_INDIRECT INDIRECT INDIRECT_INDEXED RELATIVE " - "ZEROPAGE ZEROPAGE_X ZEROPAGE_Y") - -InstructionType = Enum("InstructionType", "ADC AHX ALR ANC AND ARR ASL AXS BCC BCS BEQ BIT " - "BMI BNE BPL BRK BVC BVS CLC CLD CLI CLV CMP CPX " - "CPY DCP DEC DEX DEY EOR INC INX INY ISC JMP JSR " - "KIL LAS LAX LDA LDX LDY LSR NOP ORA PHA PHP PLA " - "PLP RLA ROL ROR RRA RTI RTS SAX SBC SEC SED SEI " - "SHX SHY SLO SRE STA STX STY TAS TAX TAY TSX TXA " +MemMode = Enum("MemMode", "DUMMY ABSOLUTE ABSOLUTE_X ABSOLUTE_Y ACCUMULATOR " + "IMMEDIATE IMPLIED INDEXED_INDIRECT INDIRECT " + "INDIRECT_INDEXED RELATIVE ZEROPAGE ZEROPAGE_X " + "ZEROPAGE_Y") + +InstructionType = Enum("InstructionType", "ADC AHX ALR ANC AND ARR ASL AXS " + "BCC BCS BEQ BIT BMI BNE BPL BRK " + "BVC BVS CLC CLD CLI CLV CMP CPX " + "CPY DCP DEC DEX DEY EOR INC INX " + "INY ISC JMP JSR KIL LAS LAX LDA " + "LDX LDY LSR NOP ORA PHA PHP PLA " + "PLP RLA ROL ROR RRA RTI RTS SAX " + "SBC SEC SED SEI SHX SHY SLO SRE " + "STA STX STY TAS TAX TAY TSX TXA " "TXS TYA XAA") @@ -79,7 +83,8 @@ def __init__(self, ppu: PPU, rom: ROM): self.Y: int = 0 self.SP: int = STACK_POINTER_RESET self.PC: int = self.read_memory(RESET_VECTOR, MemMode.ABSOLUTE) | \ - (self.read_memory(RESET_VECTOR + 1, MemMode.ABSOLUTE) << 8) + (self.read_memory(RESET_VECTOR + 1, + MemMode.ABSOLUTE) << 8) # Flags self.C: bool = False # Carry self.Z: bool = False # Zero @@ -371,7 +376,8 @@ def AND(self, instruction: Instruction, data: int): # arithmetic shift left def ASL(self, instruction: Instruction, data: int): - src = self.A if instruction.mode == MemMode.ACCUMULATOR else self.read_memory(data, instruction.mode) + src = self.A if instruction.mode == MemMode.ACCUMULATOR else ( + self.read_memory(data, instruction.mode)) self.C = bool(src >> 7) # carry is set to 7th bit src = (src << 1) & 0xFF self.setZN(src) @@ -556,7 +562,8 @@ def LDY(self, instruction: Instruction, data: int): # logical shift right def LSR(self, instruction: Instruction, data: int): - src = self.A if instruction.mode == MemMode.ACCUMULATOR else self.read_memory(data, instruction.mode) + src = self.A if instruction.mode == MemMode.ACCUMULATOR else ( + self.read_memory(data, instruction.mode)) self.C = bool(src & 1) # carry is set to 0th bit src >>= 1 self.setZN(src) @@ -580,7 +587,8 @@ def PHA(self, instruction: Instruction, data: int): # push status def PHP(self, instruction: Instruction, data: int): - self.B = True # http://nesdev.com/the%20'B'%20flag%20&%20BRK%20instruction.txt + # http://nesdev.com/the%20'B'%20flag%20&%20BRK%20instruction.txt + self.B = True self.stack_push(self.status) self.B = False @@ -595,7 +603,8 @@ def PLP(self, instruction: Instruction, data: int): # rotate one bit left def ROL(self, instruction: Instruction, data: int): - src = self.A if instruction.mode == MemMode.ACCUMULATOR else self.read_memory(data, instruction.mode) + src = self.A if instruction.mode == MemMode.ACCUMULATOR else ( + self.read_memory(data, instruction.mode)) old_c = self.C self.C = bool((src >> 7) & 1) # carry is set to 7th bit src = ((src << 1) | old_c) & 0xFF @@ -607,7 +616,8 @@ def ROL(self, instruction: Instruction, data: int): # rotate one bit right def ROR(self, instruction: Instruction, data: int): - src = self.A if instruction.mode == MemMode.ACCUMULATOR else self.read_memory(data, instruction.mode) + src = self.A if instruction.mode == MemMode.ACCUMULATOR else ( + self.read_memory(data, instruction.mode)) old_c = self.C self.C = bool(src & 1) # carry is set to 0th bit src = ((src >> 1) | (old_c << 7)) & 0xFF @@ -639,7 +649,8 @@ def RTS(self, instruction: Instruction, data: int): def SBC(self, instruction: Instruction, data: int): src = self.read_memory(data, instruction.mode) signed_result = self.A - src - (1 - self.C) - self.V = bool((self.A ^ src) & (self.A ^ signed_result) & 0x80) # set overflow + # set overflow + self.V = bool((self.A ^ src) & (self.A ^ signed_result) & 0x80) self.A = (self.A - src - (1 - self.C)) % 256 self.C = not (signed_result < 0) # set carry self.setZN(self.A) @@ -712,16 +723,16 @@ def step(self): instruction = self.instructions[opcode] data = 0 for i in range(1, instruction.length): - data |= (self.read_memory(self.PC + i, MemMode.ABSOLUTE) << ((i - 1) * 8)) + data |= (self.read_memory(self.PC + i, + MemMode.ABSOLUTE) << ((i - 1) * 8)) - # Alternative way to call that doesn't require direct function pointers - # getattr(self, instruction.type.name)(instruction, data) instruction.method(instruction, data) if not self.jumped: self.PC += instruction.length - elif instruction.type in [InstructionType.BCC, InstructionType.BCS, InstructionType.BEQ, - InstructionType.BMI, InstructionType.BNE, InstructionType.BPL, + elif instruction.type in [InstructionType.BCC, InstructionType.BCS, + InstructionType.BEQ, InstructionType.BMI, + InstructionType.BNE, InstructionType.BPL, InstructionType.BVC, InstructionType.BVS]: # branch instructions are +1 ticks if they succeeded self.cpu_ticks += 1 @@ -744,8 +755,9 @@ def different_pages(address1: int, address2: int) -> bool: address = (data + self.Y) & 0xFFFF self.page_crossed = different_pages(address, address - self.Y) case MemMode.INDEXED_INDIRECT: - ls = self.ram[(data + self.X) & 0xFF] # 0xFF for zero-page wrapping - ms = self.ram[(data + self.X + 1) & 0xFF] # 0xFF for zero-page wrapping + # 0xFF for zero-page wrapping in next two lines + ls = self.ram[(data + self.X) & 0xFF] + ms = self.ram[(data + self.X + 1) & 0xFF] address = (ms << 8) | ls case MemMode.INDIRECT: ls = self.ram[data] @@ -754,14 +766,15 @@ def different_pages(address1: int, address2: int) -> bool: ms = self.ram[data & 0xFF00] address = (ms << 8) | ls case MemMode.INDIRECT_INDEXED: - ls = self.ram[data & 0xFF] # 0xFF for zero-page wrapping - ms = self.ram[(data + 1) & 0xFF] # 0xFF for zero-page wrapping + # 0xFF for zero-page wrapping in next two lines + ls = self.ram[data & 0xFF] + ms = self.ram[(data + 1) & 0xFF] address = (ms << 8) | ls address = (address + self.Y) & 0xFFFF self.page_crossed = different_pages(address, address - self.Y) case MemMode.RELATIVE: - address = (self.PC + 2 + data) & 0xFFFF if (data < 0x80) else (self.PC + 2 + ( - data - 256)) & 0xFFFF # signed + address = (self.PC + 2 + data) & 0xFFFF if (data < 0x80) \ + else (self.PC + 2 + (data - 256)) & 0xFFFF # signed case MemMode.ZEROPAGE: address = data case MemMode.ZEROPAGE_X: @@ -778,7 +791,7 @@ def read_memory(self, location: int, mode: MemMode) -> int: # Memory map at http://wiki.nesdev.com/w/index.php/CPU_memory_map if address < 0x2000: # main ram 2 KB goes up to 0x800 return self.ram[address % 0x800] # mirrors for next 6 KB - elif address < 0x4000: # 2000-2007 is PPU, up to 3FFF mirrors it every 8 bytes + elif address < 0x4000: # 2000-2007 is PPU, mirrors every 8 bytes temp = ((address % 8) | 0x2000) # get data from ppu register return self.ppu.read_register(temp) elif address == 0x4016: # Joypad 1 status @@ -818,13 +831,14 @@ def write_memory(self, location: int, mode: MemMode, value: int): # Memory map at http://wiki.nesdev.com/w/index.php/CPU_memory_map if address < 0x2000: # main ram 2 KB goes up to 0x800 self.ram[address % 0x800] = value # mirrors for next 6 KB - elif address < 0x3FFF: # 2000-2007 is PPU, up to 3FFF mirrors it every 8 bytes + elif address < 0x3FFF: # 2000-2007 is PPU, mirrors every 8 bytes temp = ((address % 8) | 0x2000) # write data to ppu register self.ppu.write_register(temp, value) elif address == 0x4014: # DMA Transfer of Sprite Data - from_address = value * 0x100 # this is the address to start copying from - for i in range(SPR_RAM_SIZE): # copy all 256 bytes over to sprite ram - self.ppu.spr[i] = self.read_memory((from_address + i), MemMode.ABSOLUTE) + from_address = value * 0x100 # address to start copying from + for i in range(SPR_RAM_SIZE): # copy all 256 bytes to sprite ram + self.ppu.spr[i] = self.read_memory((from_address + i), + MemMode.ABSOLUTE) # stall for 512 cycles while this completes self.stall = 512 elif address == 0x4016: # Joypad 1 @@ -860,14 +874,16 @@ def set_status(self, temp: int): self.Z = bool(temp & 0b00000010) self.I = bool(temp & 0b00000100) self.D = bool(temp & 0b00001000) - self.B = False # http://nesdev.com/the%20'B'%20flag%20&%20BRK%20instruction.txt + # http://nesdev.com/the%20'B'%20flag%20&%20BRK%20instruction.txt + self.B = False self.V = bool(temp & 0b01000000) self.N = bool(temp & 0b10000000) def trigger_NMI(self): self.stack_push((self.PC >> 8) & 0xFF) self.stack_push(self.PC & 0xFF) - self.B = True # http://nesdev.com/the%20'B'%20flag%20&%20BRK%20instruction.txt + # http://nesdev.com/the%20'B'%20flag%20&%20BRK%20instruction.txt + self.B = True self.stack_push(self.status) self.B = False self.I = True @@ -878,7 +894,9 @@ def trigger_NMI(self): def log(self) -> str: opcode = self.read_memory(self.PC, MemMode.ABSOLUTE) instruction = self.instructions[opcode] - data1 = " " if instruction.length < 2 else f"{self.read_memory(self.PC + 1, MemMode.ABSOLUTE):02X}" - data2 = " " if instruction.length < 3 else f"{self.read_memory(self.PC + 2, MemMode.ABSOLUTE):02X}" + data1 = " " if instruction.length < 2 else f"{self.read_memory(self.PC + 1, + MemMode.ABSOLUTE):02X}" + data2 = " " if instruction.length < 3 else f"{self.read_memory(self.PC + 2, + MemMode.ABSOLUTE):02X}" return f"{self.PC:04X} {opcode:02X} {data1} {data2} {instruction.type.name}{29 * ' '}" \ f"A:{self.A:02X} X:{self.X:02X} Y:{self.Y:02X} P:{self.status:02X} SP:{self.SP:02X}" diff --git a/NESEmulator/ppu.py b/NESEmulator/ppu.py index b0b24fd..a452b64 100644 --- a/NESEmulator/ppu.py +++ b/NESEmulator/ppu.py @@ -22,14 +22,17 @@ PALETTE_SIZE = 32 NES_WIDTH = 256 NES_HEIGHT = 240 -NES_PALETTE = [0x7C7C7C, 0x0000FC, 0x0000BC, 0x4428BC, 0x940084, 0xA80020, 0xA81000, 0x881400, - 0x503000, 0x007800, 0x006800, 0x005800, 0x004058, 0x000000, 0x000000, 0x000000, - 0xBCBCBC, 0x0078F8, 0x0058F8, 0x6844FC, 0xD800CC, 0xE40058, 0xF83800, 0xE45C10, - 0xAC7C00, 0x00B800, 0x00A800, 0x00A844, 0x008888, 0x000000, 0x000000, 0x000000, - 0xF8F8F8, 0x3CBCFC, 0x6888FC, 0x9878F8, 0xF878F8, 0xF85898, 0xF87858, 0xFCA044, - 0xF8B800, 0xB8F818, 0x58D854, 0x58F898, 0x00E8D8, 0x787878, 0x000000, 0x000000, - 0xFCFCFC, 0xA4E4FC, 0xB8B8F8, 0xD8B8F8, 0xF8B8F8, 0xF8A4C0, 0xF0D0B0, 0xFCE0A8, - 0xF8D878, 0xD8F878, 0xB8F8B8, 0xB8F8D8, 0x00FCFC, 0xF8D8F8, 0x000000, 0x000000] +NES_PALETTE = [0x7C7C7C, 0x0000FC, 0x0000BC, 0x4428BC, 0x940084, 0xA80020, + 0xA81000, 0x881400, 0x503000, 0x007800, 0x006800, 0x005800, + 0x004058, 0x000000, 0x000000, 0x000000, 0xBCBCBC, 0x0078F8, + 0x0058F8, 0x6844FC, 0xD800CC, 0xE40058, 0xF83800, 0xE45C10, + 0xAC7C00, 0x00B800, 0x00A800, 0x00A844, 0x008888, 0x000000, + 0x000000, 0x000000, 0xF8F8F8, 0x3CBCFC, 0x6888FC, 0x9878F8, + 0xF878F8, 0xF85898, 0xF87858, 0xFCA044, 0xF8B800, 0xB8F818, + 0x58D854, 0x58F898, 0x00E8D8, 0x787878, 0x000000, 0x000000, + 0xFCFCFC, 0xA4E4FC, 0xB8B8F8, 0xD8B8F8, 0xF8B8F8, 0xF8A4C0, + 0xF0D0B0, 0xFCE0A8, 0xF8D878, 0xD8F878, 0xB8F8B8, 0xB8F8D8, + 0x00FCFC, 0xF8D8F8, 0x000000, 0x000000] class PPU: @@ -58,7 +61,8 @@ def __init__(self, rom: ROM): self.buffer2007 = 0 self.scanline = 0 self.cycle = 0 - self.display_buffer = np.zeros((NES_WIDTH, NES_HEIGHT), dtype=np.uint32) # pixels for screen + # pixels for screen + self.display_buffer = np.zeros((NES_WIDTH, NES_HEIGHT), dtype=np.uint32) # rendering reference https://wiki.nesdev.com/w/index.php/PPU_rendering # status reference http://wiki.nesdev.com/w/index.php/PPU_registers#PPUSTATUS @@ -72,7 +76,8 @@ def step(self): if (self.scanline == 241) and (self.cycle == 1): self.status |= 0b10000000 # set vblank if (self.scanline == 261) and (self.cycle == 1): - self.status |= 0b00011111 # vblank off, clear sprite zero, clear sprite overflow + # vblank off, clear sprite zero, clear sprite overflow + self.status |= 0b00011111 self.cycle += 1 if self.cycle > 340: @@ -92,7 +97,8 @@ def draw_background(self): attry = y // 4 attribute_address = attribute_table_address + attry * 8 + attrx attribute_entry = self.read_memory(attribute_address) - block = (y & 0x02) | ((x & 0x02) >> 1) # https://forums.nesdev.com/viewtopic.php?f=10&t=13315 + # https://forums.nesdev.com/viewtopic.php?f=10&t=13315 + block = (y & 0x02) | ((x & 0x02) >> 1) attribute_bits = 0 if block == 0: attribute_bits = (attribute_entry & 0b00000011) << 2 @@ -150,7 +156,8 @@ def draw_sprites(self, background_transparent: bool): if not flip_x: x_loc = 7 - x_loc - bit1and0 = (((bit1s >> x_loc) & 1) << 1) | (((bit0s >> x_loc) & 1) << 0) + bit1and0 = (((bit1s >> x_loc) & 1) << 1) | ( + ((bit0s >> x_loc) & 1) << 0) if bit1and0 == 0: # transparent pixel... skip continue @@ -166,7 +173,7 @@ def draw_sprites(self, background_transparent: bool): continue # background sprite shouldn't draw over opaque pixels color = bit3and2 | bit1and0 - color = self.read_memory(0x3F10 + color) # pull from palette + color = self.read_memory(0x3F10 + color) # from palette self.display_buffer[x, y] = NES_PALETTE[color] def read_register(self, address: int) -> int: @@ -184,10 +191,11 @@ def read_register(self, address: int) -> int: else: value = self.read_memory(self.addr) self.buffer2007 = self.read_memory(self.addr - 0x1000) - self.addr += self.address_increment # every read to $2007 there is an increment + # every read to $2007 there is an increment + self.addr += self.address_increment return value else: - raise LookupError(f"Error: Unrecognized PPU register read {address:X}") + raise LookupError(f"Error: Unrecognized PPU read {address:X}") def write_register(self, address: int, value: int): if address == 0x2000: # Control1 @@ -208,7 +216,8 @@ def write_register(self, address: int, value: int): self.spr_address += 1 elif address == 0x2005: # scroll pass - elif address == 0x2006: # based on http://wiki.nesdev.com/w/index.php/PPU_scrolling + elif address == 0x2006: + # based on http://wiki.nesdev.com/w/index.php/PPU_scrolling if not self.addr_write_latch: # first write self.addr = (self.addr & 0x00FF) | ((value & 0xFF) << 8) else: # second write @@ -218,7 +227,7 @@ def write_register(self, address: int, value: int): self.write_memory(self.addr, value) self.addr += self.address_increment else: - raise LookupError(f"Error: Unrecognized PPU register write {address:X}") + raise LookupError(f"Error: Unrecognized PPU write {address:X}") def read_memory(self, address: int) -> int: address = address % 0x4000 # mirror >0x4000 @@ -240,7 +249,7 @@ def read_memory(self, address: int) -> int: address = address - 0x10 return self.palette[address] else: - raise LookupError(f"Error: Unrecognized PPU address read at {address:X}") + raise LookupError(f"Error: Unrecognized PPU read at {address:X}") def write_memory(self, address: int, value: int): address = address % 0x4000 # mirror >0x4000 @@ -262,4 +271,4 @@ def write_memory(self, address: int, value: int): address = address - 0x10 self.palette[address] = value else: - raise LookupError(f"Error: Unrecognized PPU address read at {address:X}") + raise LookupError(f"Error: Unrecognized PPU write at {address:X}") diff --git a/NESEmulator/rom.py b/NESEmulator/rom.py index ea1490f..4333157 100644 --- a/NESEmulator/rom.py +++ b/NESEmulator/rom.py @@ -17,7 +17,8 @@ from collections import namedtuple from array import array -Header = namedtuple("Header", "signature prg_rom_size chr_rom_size flags6 flags7 flags8 flags9 flags10 unused") +Header = namedtuple("Header", "signature prg_rom_size chr_rom_size " + "flags6 flags7 flags8 flags9 flags10 unused") HEADER_SIZE = 16 TRAINER_SIZE = 512 PRG_ROM_BASE_UNIT_SIZE = 16384 @@ -29,13 +30,15 @@ class ROM: def __init__(self, filename: str): with open(filename, "rb") as file: # Read Header and Check Signature "NES" - self.header = Header._make(unpack("!LBBBBBBB5s", file.read(HEADER_SIZE))) + self.header = Header._make(unpack("!LBBBBBBB5s", + file.read(HEADER_SIZE))) if self.header.signature != 0x4E45531A: print("Invalid ROM Header Signature") else: print("Valid ROM Header Signature") # Untangle Mapper - one nybble in flags6 and one nybble in flags7 - self.mapper = (self.header.flags7 & 0xF0) | ((self.header.flags6 & 0xF0) >> 4) + self.mapper = (self.header.flags7 & 0xF0) | ( + (self.header.flags6 & 0xF0) >> 4) print(f"Mapper {self.mapper}") if self.mapper != 0: print("Invalid Mapper: Only Mapper 0 is Implemented") @@ -48,9 +51,11 @@ def __init__(self, filename: str): # Check mirroring from flags6 bit 0 self.vertical_mirroring = bool(self.header.flags6 & 1) print(f"Has vertical mirroring {self.vertical_mirroring}") - # Read PRG_ROM and CHR_ROM, these are in multiples of 16K and 8K respectively - self.prg_rom = file.read(PRG_ROM_BASE_UNIT_SIZE * self.header.prg_rom_size) - self.chr_rom = file.read(CHR_ROM_BASE_UNIT_SIZE * self.header.chr_rom_size) + # Read PRG_ROM & CHR_ROM, in multiples of 16K and 8K respectively + self.prg_rom = file.read(PRG_ROM_BASE_UNIT_SIZE * + self.header.prg_rom_size) + self.chr_rom = file.read(CHR_ROM_BASE_UNIT_SIZE * + self.header.chr_rom_size) self.prg_ram = array('B', [0] * PRG_RAM_SIZE) # ram def read_mapper0(self, address: int) -> int: @@ -64,7 +69,7 @@ def read_mapper0(self, address: int) -> int: else: return self.prg_rom[(address - 0x8000) % PRG_ROM_BASE_UNIT_SIZE] else: - raise LookupError(f"Tried to read from cartridge at invalid address {address:X}") + raise LookupError(f"Tried to read at invalid address {address:X}") def write_mapper0(self, address: int, value: int): if address >= 0x6000: diff --git a/NanoBASIC/__main__.py b/NanoBASIC/__main__.py index 0460453..004392a 100644 --- a/NanoBASIC/__main__.py +++ b/NanoBASIC/__main__.py @@ -19,6 +19,7 @@ if __name__ == "__main__": # Parse the file argument file_parser = ArgumentParser("NanoBASIC") - file_parser.add_argument("basic_file", help="A text file containing NanoBASIC code.") + file_parser.add_argument("basic_file", + help="A text file containing NanoBASIC code.") arguments = file_parser.parse_args() execute(arguments.basic_file) diff --git a/NanoBASIC/interpreter.py b/NanoBASIC/interpreter.py index f99ae04..979a33f 100644 --- a/NanoBASIC/interpreter.py +++ b/NanoBASIC/interpreter.py @@ -32,7 +32,8 @@ def __init__(self, message: str, node: Node): self.column = node.col_start def __str__(self): - return f"{self.message} Occurred at line {self.line_num} and column {self.column}" + return (f"{self.message} Occurred at line {self.line_num} " + f"and column {self.column}") def __init__(self, statements: list[Statement]): self.statements = statements @@ -44,8 +45,8 @@ def __init__(self, statements: list[Statement]): def current(self) -> Statement: return self.statements[self.statement_index] - # Returns the index of a *line_id* using a binary search, or None if not found - # Assumes the statements list is sorted + # Returns the index of a *line_id* using a binary search, + # or None if not found; Assumes the statements list is sorted def find_line_index(self, line_id: int) -> int | None: low: int = 0 high: int = len(self.statements) - 1 diff --git a/NanoBASIC/nodes.py b/NanoBASIC/nodes.py index 4eda186..cc90b7d 100644 --- a/NanoBASIC/nodes.py +++ b/NanoBASIC/nodes.py @@ -41,7 +41,7 @@ class Statement(Node): # A numeric expression is something that can be computed into a number -# This is a super class of literals, variables and simple arithmetic operations +# This is a super class of literals, variables & simple arithmetic operations @dataclass(frozen=True) class NumericExpression(Node): pass @@ -120,7 +120,7 @@ class ReturnStatement(Statement): pass -# A PRINT statement with all the things that it is meant to print (comma separated) +# A PRINT statement with all that it is meant to print (comma separated) @dataclass(frozen=True) class PrintStatement(Statement): printables: list[str | NumericExpression] diff --git a/NanoBASIC/parser.py b/NanoBASIC/parser.py index 80c5d55..6c038f6 100644 --- a/NanoBASIC/parser.py +++ b/NanoBASIC/parser.py @@ -39,7 +39,8 @@ def __init__(self, message: str, token: Token): self.column = token.col_start def __str__(self): - return f"{self.message} Occurred at line {self.line_num} and column {self.column}" + return (f"{self.message} Occurred at line {self.line_num} " + f"and column {self.column}") def __init__(self, tokens: list[Token]): self.tokens = tokens @@ -52,7 +53,8 @@ def out_of_tokens(self) -> bool: @property def current(self) -> Token: if self.out_of_tokens: - raise (Parser.ParserError(f"No tokens after {self.previous.kind}.", self.previous)) + raise (Parser.ParserError(f"No tokens after " + f"{self.previous.kind}", self.previous)) return self.tokens[self.token_index] @property @@ -91,7 +93,8 @@ def parse_statement(self, line_id: int) -> Statement: return self.parse_gosub(line_id) case TokenType.RETURN_T: return self.parse_return(line_id) - raise Parser.ParserError("Expected to find start of statement.", self.current) + raise Parser.ParserError("Expected to find start of statement.", + self.current) # PRINT "COMMA",SEPARATED,7154 def parse_print(self, line_id: int) -> PrintStatement: diff --git a/NanoBASIC/tokenizer.py b/NanoBASIC/tokenizer.py index c281e55..ebdadca 100644 --- a/NanoBASIC/tokenizer.py +++ b/NanoBASIC/tokenizer.py @@ -78,8 +78,8 @@ def tokenize(text_file: TextIO) -> list[Token]: while len(line) > 0: found: re.Match | None = None for possibility in TokenType: - # Try each pattern on the beginning of the text case-insensitive - # if it's found, store the match in *found* + # Try each pattern from the beginning, case-insensitive + # If it's found, store the match in *found* found = re.match(possibility.pattern, line, re.IGNORECASE) if found: col_end: int = col_start + found.end() - 1 @@ -92,18 +92,19 @@ def tokenize(text_file: TextIO) -> list[Token]: associated_value = int(found.group(0)) elif possibility is TokenType.VARIABLE: associated_value = found.group() - elif possibility is TokenType.STRING: # Remove quote characters + elif possibility is TokenType.STRING: + # Remove quote characters associated_value = found.group(0)[1:-1] - tokens.append(Token(possibility, line_num, col_start, col_end, - associated_value)) + tokens.append(Token(possibility, line_num, col_start, + col_end, associated_value)) # Continue search from place in line after token line = line[found.end():] col_start = col_end + 1 break # Go around again for next token - # If we went through all of the tokens and none of them were a match + # If we went through all the tokens and none of them were a match # then this must be an invalid token if not found: - print(f"Syntax error on line {line_num} and column {col_start}") + print(f"Syntax error on line {line_num} column {col_start}") break return tokens diff --git a/RetroDither/__main__.py b/RetroDither/__main__.py index a7d27e1..76dbec4 100644 --- a/RetroDither/__main__.py +++ b/RetroDither/__main__.py @@ -37,8 +37,8 @@ def prepare(file_name: str) -> Image.Image: if __name__ == "__main__": argument_parser = ArgumentParser("RetroDither") - argument_parser.add_argument("image_file", help="The input image file.") - argument_parser.add_argument("output_file", help="The resulting MacPaint file.") + argument_parser.add_argument("image_file", help="Input image file.") + argument_parser.add_argument("output_file", help="Resulting MacPaint file.") argument_parser.add_argument('-g', '--gif', default=False, action='store_true', help='Create an output gif as well.') arguments = argument_parser.parse_args() diff --git a/RetroDither/dither.py b/RetroDither/dither.py index 077f440..d7616a2 100644 --- a/RetroDither/dither.py +++ b/RetroDither/dither.py @@ -27,8 +27,9 @@ class PatternPart(NamedTuple): denominator: int -ATKINSON = [PatternPart(1, 0, 1, 8), PatternPart(2, 0, 1, 8), PatternPart(-1, 1, 1, 8), - PatternPart(0, 1, 1, 8), PatternPart(1, 1, 1, 8), PatternPart(0, 2, 1, 8)] +ATKINSON = [PatternPart(1, 0, 1, 8), PatternPart(2, 0, 1, 8), + PatternPart(-1, 1, 1, 8), PatternPart(0, 1, 1, 8), + PatternPart(1, 1, 1, 8), PatternPart(0, 2, 1, 8)] # Assumes we are working with a grayscale image (Mode "L" in Pillow) diff --git a/tests/test_knn.py b/tests/test_knn.py index a523cfd..00bdb76 100644 --- a/tests/test_knn.py +++ b/tests/test_knn.py @@ -62,7 +62,8 @@ def setUp(self) -> None: def test_digits_test_set(self): k: int = 1 - digits_knn = KNN(Digit, '../KNN/datasets/digits/digits.csv', has_header=False) + digits_knn = KNN(Digit, '../KNN/datasets/digits/digits.csv', + has_header=False) test_data_points: list[Digit] = [] with open('../KNN/datasets/digits/digits_test.csv', 'r') as f: reader = csv.reader(f) @@ -73,8 +74,10 @@ def test_digits_test_set(self): predicted_digit: str = digits_knn.classify(k, test_data_point) if predicted_digit == test_data_point.kind: correct_classifications += 1 - correct_percentage = correct_classifications / len(test_data_points) * 100 - print(f"Correct Classifications: {correct_classifications} out of {len(test_data_points)} " + correct_percentage = (correct_classifications + / len(test_data_points) * 100) + print(f"Correct Classifications: " + f"{correct_classifications} of {len(test_data_points)} " f"or {correct_percentage}%") self.assertGreater(correct_percentage, 97.0) diff --git a/tests/test_nesemulator.py b/tests/test_nesemulator.py index a1b38cc..4b36613 100644 --- a/tests/test_nesemulator.py +++ b/tests/test_nesemulator.py @@ -43,8 +43,10 @@ def test_nes_test(self): while log_line < 5260: # go until first unofficial opcode test our_line = cpu.log() correct_line = correct_lines[log_line - 1] - self.assertEqual(correct_line[0:14], our_line[0:14], f"PC/Opcode doesn't match at line {log_line}") - self.assertEqual(correct_line[48:73], our_line[48:73], f"Registers don't match at line {log_line}") + self.assertEqual(correct_line[0:14], our_line[0:14], + f"PC/Opcode doesn't match at line {log_line}") + self.assertEqual(correct_line[48:73], our_line[48:73], + f"Registers don't match at line {log_line}") cpu.step() log_line += 1 @@ -53,11 +55,12 @@ def test_blargg_instr_test_v5_basics(self): rom = ROM("../NESEmulator/Tests/instr_test-v5/rom_singles/01-basics.nes") ppu = PPU(rom) cpu = CPU(ppu, rom) - # Test keeps running as long as $6000 is 80, and then $6000 is result code; 0 means success + # Tests run as long as $6000 is 80, and then $6000 is result code; 0 means success rom.prg_ram[0] = 0x80 while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test cpu.step() - self.assertEqual(0, rom.prg_ram[0], f"Result code of basics test is {rom.prg_ram[0]} not 0") + self.assertEqual(0, rom.prg_ram[0], + f"Result code of basics test is {rom.prg_ram[0]} not 0") message = bytes(rom.prg_ram[4:]).decode("utf-8") print(message[0:message.index("\0")]) # Message ends with null terminator @@ -66,11 +69,12 @@ def test_blargg_instr_test_v5_implied(self): rom = ROM("../NESEmulator/Tests/instr_test-v5/rom_singles/02-implied.nes") ppu = PPU(rom) cpu = CPU(ppu, rom) - # Test keeps running as long as $6000 is 80, and then $6000 is result code; 0 means success + # Tests run as long as $6000 is 80, and then $6000 is result code; 0 means success rom.prg_ram[0] = 0x80 while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test cpu.step() - self.assertEqual(0, rom.prg_ram[0], f"Result code of implied test is {rom.prg_ram[0]} not 0") + self.assertEqual(0, rom.prg_ram[0], + f"Result code of implied test is {rom.prg_ram[0]} not 0") message = bytes(rom.prg_ram[4:]).decode("utf-8") print(message[0:message.index("\0")]) # Message ends with null terminator @@ -79,11 +83,12 @@ def test_blargg_instr_test_v5_branches(self): rom = ROM("../NESEmulator/Tests/instr_test-v5/rom_singles/10-branches.nes") ppu = PPU(rom) cpu = CPU(ppu, rom) - # Test keeps running as long as $6000 is 80, and then $6000 is result code; 0 means success + # Tests run as long as $6000 is 80, and then $6000 is result code; 0 means success rom.prg_ram[0] = 0x80 while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test cpu.step() - self.assertEqual(0, rom.prg_ram[0], f"Result code of braches test is {rom.prg_ram[0]} not 0") + self.assertEqual(0, rom.prg_ram[0], + f"Result code of braches test is {rom.prg_ram[0]} not 0") message = bytes(rom.prg_ram[4:]).decode("utf-8") print(message[0:message.index("\0")]) # Message ends with null terminator @@ -92,11 +97,12 @@ def test_blargg_instr_test_v5_stack(self): rom = ROM("../NESEmulator/Tests/instr_test-v5/rom_singles/11-stack.nes") ppu = PPU(rom) cpu = CPU(ppu, rom) - # Test keeps running as long as $6000 is 80, and then $6000 is result code; 0 means success + # Tests run as long as $6000 is 80, and then $6000 is result code; 0 means success rom.prg_ram[0] = 0x80 while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test cpu.step() - self.assertEqual(0, rom.prg_ram[0], f"Result code of stack test is {rom.prg_ram[0]} not 0") + self.assertEqual(0, rom.prg_ram[0], + f"Result code of stack test is {rom.prg_ram[0]} not 0") message = bytes(rom.prg_ram[4:]).decode("utf-8") print(message[0:message.index("\0")]) # Message ends with null terminator @@ -105,11 +111,12 @@ def test_blargg_instr_test_v5_jmp_jsr(self): rom = ROM("../NESEmulator/Tests/instr_test-v5/rom_singles/12-jmp_jsr.nes") ppu = PPU(rom) cpu = CPU(ppu, rom) - # Test keeps running as long as $6000 is 80, and then $6000 is result code; 0 means success + # Tests run as long as $6000 is 80, and then $6000 is result code; 0 means success rom.prg_ram[0] = 0x80 while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test cpu.step() - self.assertEqual(0, rom.prg_ram[0], f"Result code of jmp_jsr test is {rom.prg_ram[0]} not 0") + self.assertEqual(0, rom.prg_ram[0], + f"Result code of jmp_jsr test is {rom.prg_ram[0]} not 0") message = bytes(rom.prg_ram[4:]).decode("utf-8") print(message[0:message.index("\0")]) # Message ends with null terminator @@ -118,11 +125,12 @@ def test_blargg_instr_test_v5_rts(self): rom = ROM("../NESEmulator/Tests/instr_test-v5/rom_singles/13-rts.nes") ppu = PPU(rom) cpu = CPU(ppu, rom) - # Test keeps running as long as $6000 is 80, and then $6000 is result code; 0 means success + # Tests run as long as $6000 is 80, and then $6000 is result code; 0 means success rom.prg_ram[0] = 0x80 while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test cpu.step() - self.assertEqual(0, rom.prg_ram[0], f"Result code of rts test is {rom.prg_ram[0]} not 0") + self.assertEqual(0, rom.prg_ram[0], + f"Result code of rts test is {rom.prg_ram[0]} not 0") message = bytes(rom.prg_ram[4:]).decode("utf-8") print(message[0:message.index("\0")]) # Message ends with null terminator @@ -131,11 +139,12 @@ def test_blargg_instr_test_v5_rti(self): rom = ROM("../NESEmulator/Tests/instr_test-v5/rom_singles/14-rti.nes") ppu = PPU(rom) cpu = CPU(ppu, rom) - # Test keeps running as long as $6000 is 80, and then $6000 is result code; 0 means success + # Tests run as long as $6000 is 80, and then $6000 is result code; 0 means success rom.prg_ram[0] = 0x80 while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test cpu.step() - self.assertEqual(0, rom.prg_ram[0], f"Result code of rti test is {rom.prg_ram[0]} not 0") + self.assertEqual(0, rom.prg_ram[0], + f"Result code of rti test is {rom.prg_ram[0]} not 0") message = bytes(rom.prg_ram[4:]).decode("utf-8") print(message[0:message.index("\0")]) # Message ends with null terminator @@ -144,26 +153,28 @@ def test_blargg_instr_test_v5_brk(self): rom = ROM("../NESEmulator/Tests/instr_test-v5/rom_singles/15-brk.nes") ppu = PPU(rom) cpu = CPU(ppu, rom) - # Test keeps running as long as $6000 is 80, and then $6000 is result code; 0 means success + # Tests run as long as $6000 is 80, and then $6000 is result code; 0 means success rom.prg_ram[0] = 0x80 while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test cpu.step() message = bytes(rom.prg_ram[4:]).decode("utf-8") print(message[0:message.index("\0")]) # Message ends with null terminator - self.assertEqual(0, rom.prg_ram[0], f"Result code of brk test is {rom.prg_ram[0]} not 0") + self.assertEqual(0, rom.prg_ram[0], + f"Result code of brk test is {rom.prg_ram[0]} not 0") def test_blargg_instr_test_v5_special(self): # Create machinery that we are testing rom = ROM("../NESEmulator/Tests/instr_test-v5/rom_singles/16-special.nes") ppu = PPU(rom) cpu = CPU(ppu, rom) - # Test keeps running as long as $6000 is 80, and then $6000 is result code; 0 means success + # Tests run as long as $6000 is 80, and then $6000 is result code; 0 means success rom.prg_ram[0] = 0x80 while rom.prg_ram[0] == 0x80: # go until first unofficial opcode test cpu.step() message = bytes(rom.prg_ram[4:]).decode("utf-8") print(message[0:message.index("\0")]) # Message ends with null terminator - self.assertEqual(0, rom.prg_ram[0], f"Result code of special test is {rom.prg_ram[0]} not 0") + self.assertEqual(0, rom.prg_ram[0], + f"Result code of special test is {rom.prg_ram[0]} not 0") if __name__ == "__main__":