Skip to content

Commit 5ae6b6d

Browse files
authored
Merge pull request #17 from craigthomas/python-36-upgrade
Python 36 Upgrade
2 parents f8759ce + 0e07133 commit 5ae6b6d

File tree

8 files changed

+118
-86
lines changed

8 files changed

+118
-86
lines changed

.travis.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
dist: bionic
12
language: python
23
sudo: false
34
python:
4-
- 2.7
5+
- 3.6
56
env:
67
- DISPLAY=:99.0
78
addons:
@@ -31,6 +32,6 @@ services:
3132
virtalenv:
3233
system_site_packages: true
3334
script:
34-
- nosetests -v --with-coverage --cover-package=chip8
35+
- coverage run -m nose
3536
after_success:
3637
- bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports"

README.md

Lines changed: 38 additions & 28 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
@@ -66,41 +66,43 @@ and run the emulator in, without touching your master Python environment.
6666

6767
### Ubuntu Installation
6868

69-
The installation under Ubuntu requires several different steps:
69+
The installation under Ubuntu 20.04 requires several different steps:
7070

7171
1. Install SDL libraries. The SDL (Simple DirectMedia Layer) libraries are used by PyGame to draw
7272
images on the screen. Several other dependencies are needed by SDL in order to install PyGame.
7373
To install the required SDL libraries (plus dependencies) from the command-line:
7474

7575
```
76-
sudo apt-get install libfreetype6-dev libsdl-dev libsdl-image1.2-dev \
77-
libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsdl-sound1.2-dev \
78-
libportmidi-dev python-dev
76+
sudo apt install python3 python3-dev libsdl-dev libfreetype6-dev \
77+
libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsdl-sound1.2-dev \
78+
libportmidi-dev
7979
```
8080

8181
2. Install PIP. The `pip` package manager is used for managing Python packages. To install `pip`
8282
from the command-line:
8383

8484
```
85-
sudo apt-get install python-pip
85+
sudo apt install python3-pip
8686
```
8787

8888
3. (*Optional*) Install virtual environment support for Python:
8989

9090
1. Install virtual environment support:
9191

9292
```
93-
pip install virtualenv
94-
pip install virtualenvwrapper
93+
pip3 install virtualenv
94+
pip3 install virtualenvwrapper
9595
```
9696
9797
2. First you must update your `.bashrc` file in the your home directory and add a few lines
9898
to the bottom of that file:
9999
100100
```
101101
cat >> ~/.bashrc << EOF
102+
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
102103
export WORKON_HOME=$HOME/.virtualenvs
103-
source /usr/local/bin/virtualenvwrapper.sh
104+
export PATH=$PATH:$HOME/.local/bin
105+
source $HOME/.local/bin/virtualenvwrapper.sh
104106
EOF
105107
```
106108
@@ -119,7 +121,7 @@ from the command-line:
119121
5. Clone (or download) the Chip 8 emulator project:
120122
121123
```
122-
sudo apt-get install git
124+
sudo apt install git
123125
git clone https://github.com/craigthomas/Chip8Python.git
124126
```
125127
@@ -132,8 +134,9 @@ from the command-line:
132134
133135
### Windows Installation
134136
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.
137+
1. Download and install [Python 3.6.8 for Windows](https://www.python.org/downloads/release/python-368/).
138+
Make sure that `pip` and `Add python.exe to Path` options are checked when performing the installation. Later
139+
versions of Python 3 are also likely to work correctly with the emulator.
137140
138141
2. (*Optional*) Install virtual environment support for Python. Run the following commands from a command prompt:
139142
@@ -170,34 +173,35 @@ in the directory where you cloned or downloaded the source files:
170173
171174
### Running a ROM
172175
176+
Note that if you created a virtual environment as detailed above,
177+
you will need to `workon` that environment before starting the emulator:
178+
179+
workon chip8
180+
173181
The command-line interface requires a single argument, which is the full
174182
path to a Chip 8 ROM. Run the following command in the directory where you
175183
cloned or downloaded the source files:
176184
177-
python chip8/yac8e.py /path/to/rom/filename
185+
python yac8e.py /path/to/rom/filename
178186
179-
This will start the emulator with the specified ROM. Note that if you created
180-
a virtual environment as detailed above, you will need to `workon` that
181-
environment before starting the emulator:
182-
183-
workon chip8
187+
This will start the emulator with the specified ROM.
184188
185189
### Screen Scale
186190
187-
The `-s` switch will scale the size of the window (the original size at 1x
191+
The `--scale` switch will scale the size of the window (the original size at 1x
188192
scale is 64 x 32):
189193
190-
python chip8/yac8e.py /path/to/rom/filename -s 10
194+
python yac8e.py /path/to/rom/filename --scale 10
191195
192196
The command above will scale the window so that it is 10 times the normal
193197
size.
194198
195199
### Execution Delay
196200
197-
You may also wish to experiment with the `-d` switch, which instructs
201+
You may also wish to experiment with the `--delay` switch, which instructs
198202
the emulator to add a delay to every operation that is executed. For example,
199203
200-
python chip8/yac8e.py /path/to/rom/filename -d 10
204+
python yac8e.py /path/to/rom/filename --delay 10
201205
202206
The command above will add a 10 ms delay to every opcode that is executed.
203207
This is useful for very fast computers (note that it is difficult to find
@@ -253,11 +257,17 @@ keys that impact the execution of the emulator.
253257
254258
## ROM Compatibility
255259
256-
Here are the list of public domain ROMs and their current status with the emulator.
257-
258-
| ROM Name | Works Correctly | Notes |
259-
| :---------------: | :----------------: | :---: |
260-
| MAZE | :heavy_check_mark: | |
260+
Here are the list of public domain ROMs and their current status with the emulator, along
261+
with keypresses based on the default keymap:
262+
263+
| ROM Name | Works Correctly | Notes |
264+
| :-------- | :----------------: | :---------------------------------------------------------------------------------- |
265+
| MAZE | :heavy_check_mark: | |
266+
| MISSILE | :heavy_check_mark: | `U` fires |
267+
| PONG | :heavy_check_mark: | `4` left player up, `7` left player down, `V` right player up, `B` right player down|
268+
| TANK | :heavy_check_mark: | `R` fires, `T` moves right, `7` moves left, `5` moves down, `U` moves up |
269+
| TETRIS | :heavy_check_mark: | `R` moves left, `T` moves right, `Y` moves down, `7` rotates |
270+
| UFO | :heavy_check_mark: | `R` fires up, `T` fires right, `7` fires left |
261271
262272
263273
## 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')

0 commit comments

Comments
 (0)