Skip to content

Commit 02d0283

Browse files
committed
Update sources to use Python 3.6
1 parent f8759ce commit 02d0283

File tree

8 files changed

+94
-70
lines changed

8 files changed

+94
-70
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
language: python
22
sudo: false
33
python:
4-
- 2.7
4+
- 3.6
55
env:
66
- DISPLAY=:99.0
77
addons:
@@ -31,6 +31,6 @@ services:
3131
virtalenv:
3232
system_site_packages: true
3333
script:
34-
- nosetests -v --with-coverage --cover-package=chip8
34+
- coverage run -m nose
3535
after_success:
3636
- bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports"

README.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
## What is it?
2929

30-
This project is a Chip 8 emulator written in Python 2.7. The original purpose
30+
This project is a Chip 8 emulator written in Python 3.6+. The original purpose
3131
of the project was to create a simple learning emulator that was well
3232
documented and coded in terms that were easy to understand. It was also an
3333
exercise to learn more about Python. The result is a simple command-line
@@ -54,7 +54,7 @@ This project makes use of an MIT style license. Please see the file called LICEN
5454
Copy the source files to a directory of your choice. In addition to
5555
the source, you will need the following required software packages:
5656

57-
* [Python 2.7](http://www.python.org)
57+
* [Python 3.6.8 or better](http://www.python.org)
5858
* [pygame](http://www.pygame.org)
5959

6060
I strongly recommend creating a virtual environment using the
@@ -132,8 +132,9 @@ from the command-line:
132132
133133
### Windows Installation
134134
135-
1. Download and install [Python 2.7.15 for Windows](https://www.python.org/downloads/release/python-2715/).
136-
Make sure that `pip` and `Add python.exe to Path` options are checked when performing the installation.
135+
1. Download and install [Python 3.6.8 for Windows](https://www.python.org/downloads/release/python-368/).
136+
Make sure that `pip` and `Add python.exe to Path` options are checked when performing the installation. Later
137+
versions of Ptyhon 3 are also likely to work correctly with the emulator.
137138
138139
2. (*Optional*) Install virtual environment support for Python. Run the following commands from a command prompt:
139140
@@ -174,7 +175,7 @@ The command-line interface requires a single argument, which is the full
174175
path to a Chip 8 ROM. Run the following command in the directory where you
175176
cloned or downloaded the source files:
176177
177-
python chip8/yac8e.py /path/to/rom/filename
178+
python yac8e.py /path/to/rom/filename
178179
179180
This will start the emulator with the specified ROM. Note that if you created
180181
a virtual environment as detailed above, you will need to `workon` that
@@ -184,20 +185,20 @@ environment before starting the emulator:
184185
185186
### Screen Scale
186187
187-
The `-s` switch will scale the size of the window (the original size at 1x
188+
The `--scale` switch will scale the size of the window (the original size at 1x
188189
scale is 64 x 32):
189190
190-
python chip8/yac8e.py /path/to/rom/filename -s 10
191+
python yac8e.py /path/to/rom/filename --scale 10
191192
192193
The command above will scale the window so that it is 10 times the normal
193194
size.
194195
195196
### Execution Delay
196197
197-
You may also wish to experiment with the `-d` switch, which instructs
198+
You may also wish to experiment with the `--delay` switch, which instructs
198199
the emulator to add a delay to every operation that is executed. For example,
199200
200-
python chip8/yac8e.py /path/to/rom/filename -d 10
201+
python yac8e.py /path/to/rom/filename --delay 10
201202
202203
The command above will add a 10 ms delay to every opcode that is executed.
203204
This is useful for very fast computers (note that it is difficult to find
@@ -255,9 +256,11 @@ keys that impact the execution of the emulator.
255256
256257
Here are the list of public domain ROMs and their current status with the emulator.
257258
258-
| ROM Name | Works Correctly | Notes |
259-
| :---------------: | :----------------: | :---: |
260-
| MAZE | :heavy_check_mark: | |
259+
| ROM Name | Works Correctly | Notes |
260+
| :-------: | :----------------: | :---------------------------------------------------------------------------------: |
261+
| MAZE | :heavy_check_mark: | |
262+
| MISSILE | :heavy_check_mark: | `u` fires |
263+
| PONG | :heavy_check_mark: | `4` left player up, `7` left player down, `v` right player up, `b` right player down|
261264
262265
263266
## Further Documentation

chip8/cpu.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from pygame import key
1212
from random import randint
1313

14-
from config import (
14+
from chip8.config import (
1515
MAX_MEMORY, STACK_POINTER_START, KEY_MAPPINGS, PROGRAM_COUNTER_START
1616
)
1717

@@ -667,14 +667,14 @@ def draw_normal(self, x_pos, y_pos, num_bytes):
667667
:param y_pos: the Y position of the sprite
668668
:param num_bytes: the number of bytes to draw
669669
"""
670-
for y_index in xrange(num_bytes):
670+
for y_index in range(num_bytes):
671671

672672
color_byte = bin(self.memory[self.registers['index'] + y_index])
673673
color_byte = color_byte[2:].zfill(8)
674674
y_coord = y_pos + y_index
675675
y_coord = y_coord % self.screen.get_height()
676676

677-
for x_index in xrange(8):
677+
for x_index in range(8):
678678

679679
x_coord = x_pos + x_index
680680
x_coord = x_coord % self.screen.get_width()
@@ -704,9 +704,9 @@ def draw_extended(self, x_pos, y_pos, num_bytes):
704704
:param y_pos: the Y position of the sprite
705705
:param num_bytes: the number of bytes to draw
706706
"""
707-
for y_index in xrange(num_bytes):
707+
for y_index in range(num_bytes):
708708

709-
for x_byte in xrange(2):
709+
for x_byte in range(2):
710710

711711
color_byte = bin(self.memory[self.registers['index'] + (y_index * 2) + x_byte])
712712
color_byte = color_byte[2:].zfill(8)

chip8/yac8e.py renamed to chip8/emulator.py

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66
"""
77
# I M P O R T S ###############################################################
88

9-
import argparse
109
import pygame
1110

12-
from config import FONT_FILE, DELAY_INTERVAL
13-
from cpu import Chip8CPU
14-
from screen import Chip8Screen
11+
from chip8.config import FONT_FILE, DELAY_INTERVAL
12+
from chip8.cpu import Chip8CPU
13+
from chip8.screen import Chip8Screen
1514

1615
# C O N S T A N T S ###########################################################
1716

@@ -21,28 +20,6 @@
2120
# F U N C T I O N S ##########################################################
2221

2322

24-
def parse_arguments():
25-
"""
26-
Parses the command-line arguments passed to the emulator.
27-
28-
:return: the parsed command-line arguments
29-
"""
30-
parser = argparse.ArgumentParser(
31-
description="Starts a simple Chip 8 "
32-
"emulator. See README.md for more information, and LICENSE for "
33-
"terms of use.")
34-
parser.add_argument(
35-
"rom", help="the ROM file to load on startup")
36-
parser.add_argument(
37-
"-s", help="the scale factor to apply to the display "
38-
"(default is 5)", type=int, default=5, dest="scale")
39-
parser.add_argument(
40-
"-d", help="sets the CPU operation to take at least "
41-
"the specified number of milliseconds to execute (default is 1)",
42-
type=int, default=1, dest="op_delay")
43-
return parser.parse_args()
44-
45-
4623
def main_loop(args):
4724
"""
4825
Runs the main emulator loop with the specified arguments.
@@ -71,10 +48,4 @@ def main_loop(args):
7148
if keys_pressed[pygame.K_ESCAPE]:
7249
cpu.running = False
7350

74-
75-
# M A I N #####################################################################
76-
77-
if __name__ == "__main__":
78-
main_loop(parse_arguments())
79-
8051
# E N D O F F I L E #######################################################

chip8/screen.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -180,14 +180,14 @@ def scroll_down(self, num_lines):
180180
181181
:param num_lines: the number of lines to scroll down
182182
"""
183-
for y_pos in xrange(self.height - num_lines, -1, -1):
184-
for x_pos in xrange(self.width):
183+
for y_pos in range(self.height - num_lines, -1, -1):
184+
for x_pos in range(self.width):
185185
pixel_color = self.get_pixel(x_pos, y_pos)
186186
self.draw_pixel(x_pos, y_pos + num_lines, pixel_color)
187187

188188
# Blank out the lines above the ones we scrolled
189-
for y_pos in xrange(num_lines):
190-
for x_pos in xrange(self.width):
189+
for y_pos in range(num_lines):
190+
for x_pos in range(self.width):
191191
self.draw_pixel(x_pos, y_pos, 0)
192192

193193
self.update()
@@ -196,14 +196,14 @@ def scroll_left(self):
196196
"""
197197
Scroll the screen left 4 pixels.
198198
"""
199-
for y_pos in xrange(self.height):
200-
for x_pos in xrange(4, self.width):
199+
for y_pos in range(self.height):
200+
for x_pos in range(4, self.width):
201201
pixel_color = self.get_pixel(x_pos, y_pos)
202202
self.draw_pixel(x_pos - 4, y_pos, pixel_color)
203203

204204
# Blank out the lines to the right of the ones we just scrolled
205-
for y_pos in xrange(self.height):
206-
for x_pos in xrange(self.width - 4, self.width):
205+
for y_pos in range(self.height):
206+
for x_pos in range(self.width - 4, self.width):
207207
self.draw_pixel(x_pos, y_pos, 0)
208208

209209
self.update()
@@ -212,14 +212,14 @@ def scroll_right(self):
212212
"""
213213
Scroll the screen right 4 pixels.
214214
"""
215-
for y_pos in xrange(self.height):
216-
for x_pos in xrange(self.width - 4, -1, -1):
215+
for y_pos in range(self.height):
216+
for x_pos in range(self.width - 4, -1, -1):
217217
pixel_color = self.get_pixel(x_pos, y_pos)
218218
self.draw_pixel(x_pos + 4, y_pos, pixel_color)
219219

220220
# Blank out the lines to the left of the ones we just scrolled
221-
for y_pos in xrange(self.height):
222-
for x_pos in xrange(4):
221+
for y_pos in range(self.height):
222+
for x_pos in range(4):
223223
self.draw_pixel(x_pos, y_pos, 0)
224224

225225
self.update()

requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pygame
2-
coveralls
3-
mock
2+
mock
3+
nose
4+
coverage

test/test_chip8cpu.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -580,13 +580,13 @@ def test_draw_zero_bytes_vf_not_set(self):
580580
def test_execute_instruction_raises_exception_on_unknown_op_code(self):
581581
with self.assertRaises(UnknownOpCodeException) as context:
582582
self.cpu.execute_instruction(operand=0x8008)
583-
self.assertEqual("Unknown op-code: 8008", context.exception.message)
583+
self.assertEqual("Unknown op-code: 8008", str(context.exception))
584584

585585
def test_execute_instruction_raises_exception_on_unknown_op_code_from_cpu(self):
586586
with self.assertRaises(UnknownOpCodeException) as context:
587587
self.cpu.operand = 0x8008
588588
self.cpu.execute_instruction(operand=0x8008)
589-
self.assertEqual("Unknown op-code: 8008", context.exception.message)
589+
self.assertEqual("Unknown op-code: 8008", str(context.exception))
590590

591591
def test_execute_instruction_on_operand_in_memory(self):
592592
self.cpu.registers['pc'] = 0x200
@@ -596,7 +596,7 @@ def test_execute_instruction_on_operand_in_memory(self):
596596
self.assertEqual(0x202, self.cpu.registers['pc'])
597597

598598
def test_execute_logical_instruction_raises_exception_on_unknown_op_codes(self):
599-
for x in xrange(8, 14):
599+
for x in range(8, 14):
600600
self.cpu.operand = x
601601
with self.assertRaises(UnknownOpCodeException):
602602
self.cpu.execute_logical_instruction()
@@ -610,7 +610,7 @@ def test_misc_routines_raises_exception_on_unknown_op_codes(self):
610610
self.cpu.operand = 0x0
611611
with self.assertRaises(UnknownOpCodeException) as context:
612612
self.cpu.misc_routines()
613-
self.assertEqual("Unknown op-code: 0", context.exception.message)
613+
self.assertEqual("Unknown op-code: 0", str(context.exception))
614614

615615
def test_scroll_down_called(self):
616616
self.cpu.operand = 0x00C4
@@ -753,7 +753,9 @@ def test_str_function(self):
753753
self.cpu.operand = 0xBA
754754
self.cpu.registers['index'] = 0xDEAD
755755
result = str(self.cpu)
756-
self.assertEqual("PC: BEED OP: BA\nV0: 0\nV1: 1\nV2: 2\nV3: 3\nV4: 4\nV5: 5\nV6: 6\nV7: 7\nV8: 8\nV9: 9\nVA: A\nVB: B\nVC: C\nVD: D\nVE: E\nVF: F\nI: DEAD\n", result)
756+
self.assertEqual(
757+
"PC: BEED OP: BA\nV0: 0\nV1: 1\nV2: 2\nV3: 3\nV4: 4\nV5: 5\nV6: 6"
758+
"\nV7: 7\nV8: 8\nV9: 9\nVA: A\nVB: B\nVC: C\nVD: D\nVE: E\nVF: F\nI: DEAD\n", result)
757759

758760
def test_wait_for_keypress(self):
759761
EventMock = collections.namedtuple('EventMock', 'type')

yac8e.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""
2+
Copyright (C) 2012-2019 Craig Thomas
3+
This project uses an MIT style license - see LICENSE for details.
4+
5+
A simple Chip 8 emulator - see the README file for more information.
6+
"""
7+
# I M P O R T S ###############################################################
8+
9+
import argparse
10+
import os
11+
12+
# G L O B A L S ###############################################################
13+
14+
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
15+
16+
# F U N C T I O N S ##########################################################
17+
18+
19+
def parse_arguments():
20+
"""
21+
Parses the command-line arguments passed to the emulator.
22+
23+
:return: the parsed command-line arguments
24+
"""
25+
parser = argparse.ArgumentParser(
26+
description="Starts a simple Chip 8 "
27+
"emulator. See README.md for more information, and LICENSE for "
28+
"terms of use.")
29+
parser.add_argument(
30+
"rom", help="the ROM file to load on startup")
31+
parser.add_argument(
32+
"--scale", help="the scale factor to apply to the display "
33+
"(default is 5)", type=int, default=5, dest="scale")
34+
parser.add_argument(
35+
"--delay", help="sets the CPU operation to take at least "
36+
"the specified number of milliseconds to execute (default is 1)",
37+
type=int, default=1, dest="op_delay")
38+
return parser.parse_args()
39+
40+
41+
# M A I N #####################################################################
42+
43+
if __name__ == "__main__":
44+
from chip8.emulator import main_loop
45+
main_loop(parse_arguments())
46+
47+
# E N D O F F I L E #######################################################

0 commit comments

Comments
 (0)