Assignment (INFO1110)
Introduction
The assignment is an individual assessment. It contributes 30% of your final marks.
The due date for the assignment is on 9th May 2024, 11:59 pm (Sydney time).
This is an assignment, and staff are not permitted to give guidance on your code or how to solve a
specific problem. That is the purpose of the assessment that you are required to perform to achieve
the grade.
You may ask clarification questions about the assignment description. This is often necessary to implement
functionality that may need further understanding to complete. If you have a question to ask on Ed, please
search before asking. With a cohort of almost 2000 students, chances are that someone has already asked a
question you have planned to ask.
Do not wait too long before starting. This assignment needs time and sustained effort.
Remember that you should not be posting any assignment code publicly (including Ed), as this would
constitute academic dishonesty.
Submissions
Late submissions are not accepted unless an approved special consideration or special arrangement in the
form of a Simple Extension or Extension of time has been granted. Please inform staff if you have been
granted this.
All submissions must be made via Ed, including any supporting documentation that is produced
during the planning of the program design such as flowcharts, pseudocodes, and UML class
diagrams.
You may submit as many times before the due date, there is 0 penalty for submitting multiple times.
We will use the latest submission received before the due date for marking. Request to grade files
and derive marks from a combination of different submissions will not be accepted.
It is your responsibility to check that your submission is complete and it meets the following rules:
The Python programs must be able to compile and run within the Ed environment provided.
The Python version that is currently being used on Ed is Python 3.11.8.
Only the files given in the scaffold code will be started by the auto-marker. You are free to write
additional python files, but you must implement all functions and classes provided in the
scaffold. Ensure that you have submitted these files with the correct file name as given in the
questions' scaffold:
board_displayer.py
emitter.py
input_parser.py
laser_circuit.py
mirror.py
photon.py
receiver.py
run.py
sorter.py
Your submission must also include a circuit_for_testing.py and test.py file which
will be used for the manual grading process.
All files specified above must include your name, SID, and unikey in the following format (order
matters!). A placeholder has been provided at the top of the file in the docstring. Providing
incorrect details will cause your submission to fail all test cases.
Name: Xxx Yyy
SID: XXXXXXXXX
Unikey: xxxxXXXX
If you attempt to deceive the auto-grader, obfuscate your code, or do not answer the question by hard coding,
0 marks will be awarded for the question.
Marks
Marks are allocated by the automatic test cases passed for each section, as well as manual grading by
your tutor.
Automatic Test Cases (20/30)
Your marks for this component will be based purely on the automatic test cases you pass. There are 3
types of automatic test cases, all contributing to your mark:
Public: The name of these test cases describes what it is testing, and additionally gives you
feedback on what you got wrong e.g. incorrect output, incorrect return values from functions,
etc. Students can easily see what they got right and wrong.
Hidden: The test case is only named Hidden testcase and does not provide detailed
feedback. You will only be able to see if you passed it or not. The idea behind this is to
encourage students to carefully read through the assignment description and ensure its
reflected in their program.
Private: These tests will only be visible after the deadline. You will not know how many private
test cases there are until the assignment is graded and returned.
There are several features for this assignment, with each one having their own marking proportion.
As example, the first feature SET-MY-CIRCUIT weighs 25% of the automatic test cases. This means
passing all public, hidden and private test cases for this feature gets you 5 out of the 20 marks.
Manual Grading (10/30)
Manual grading will assess the style, layout, and comments, correctness of test case implementation
in test.py and your responses in the test_plan.md document. The test.py file will be executed
during the marking process. Style marking is only applied for reasonable attempts, those which have
code beyond the initial scaffold and are passing at least some test cases.
The style guide for this assessment can be found on the official Python website
https://peps.python.org/pep-0008/.
In addition to the official style guide, you can also refer to these resources:
Code style guide - Part 1
Code style guide - Part 2
If there's an issue running the program, the tutor will not be responsible to debug your program, so please
ensure it runs as expected before making it your final submission.
Restrictions
The following must be read, as it says what you can and can't use. A 20% penalty will be levied on all
testcases passed if one or more of the restricted codes are used in your submission.
Keywords
The following is not allowed.
for
in (this includes the use of __contains__() as in simply invokes this method)
global
lambda
nonlocal
Built-in Functions
The following is not allowed.
all()/any()
map()/filter()
min()/max()/sum()
eval()/compile()/exec()
enumerate()
globals()/locals()
Modules
The following is allowed.
sys
typing
unittest
any module you have written, e.g. emitter .
Every other module is not allowed.
Size Restrictions
A submission containing a more than 5000 lines of code, or larger than 500kB will not be accepted.
To check the file sizes of your files, use the bash commands wc -l *.py and du -skc *.py .
Individual files, such as run.py can be checked with wc -l run.py and du -skc run.py
Help and Feedback
You are encouraged to ask questions about the assignment during the Helpdesk and on the Ed
discussion board. However, remember that you should not be posting any assignment code
publicly, as this would constitute academic dishonesty. Also, you should not disclose your code
or talk about your solutions in any of the PASS sessions.
Friendly Reminder
On occasion, typos or other errors may appear in the assignment description. Sometimes the
description could be clearer. Students and tutors often make great suggestions for improving the
description. Therefore, this assignment description may be clarified up to Week 8, Monday 15,
April. No changes will be made. Revised versions will be clearly marked in the Log of Changes slide
and the most recent version will be updated in the assignment description.
Academic Declaration
By submitting this assignment, you declare the following:
I declare that I have read and understood the University of Sydney Student Plagiarism: Coursework Policy
and Procedure, and except where specifically acknowledged, the work contained in this assignment is my
own work and has not been copied from other sources or been previously submitted for award or
assessment. I also did not use any generative AI tools (including ChatGPT) to assist in writing this
assignment.
I understand that failure to comply with the Student Plagiarism: Coursework Policy and Procedure can
lead to severe penalties as outlined under Chapter 8 of the University of Sydney By-Law 1999 (as
amended). These penalties may be imposed in cases where any significant portion of my submitted work
has been copied without proper acknowledgment from other sources, including published works, the
Internet, existing programs, the work of other students, or work previously submitted for other awards or
assessments.
I realize that I may be asked to identify those portions of the work contributed by me and required to
demonstrate my knowledge of the relevant material by answering oral questions or by undertaking
supplementary work, either written or in the laboratory, in order to arrive at the final assessment mark.
I acknowledge that the School of Computer Science, in assessing this assignment, may reproduce it
entirely, may provide a copy to another member of faculty, and/or communicate a copy of this
assignment to a plagiarism checking service or in-house computer program, and that a copy of the
assignment may be maintained by the service or the School of Computer Science for the purpose of future
plagiarism checking.
Any attempts to trick, break or circumstancing the automate marking system may leads to a mark of 0 and will
be reported to academic honesty committee.
Assignment Breakdown
You will be implementing and emulating a (very rough approximation of) a photonic circuit. In a highlevel overview, photonic circuits use lasers to emit photons (particles of light) which perform
computation through their interactions with other photonic components. There are many parts we
are leaving out, however our main goal is to build a simple emulation of the system which will give
you first-hand experience on implementing a coding project from the ground-up, and hopefully be
interesting enough for you to enjoy.
You do not need any understanding of physics for this assignment, and indeed we will be doing it a degree of
discourtesy by violating rules of quantum mechanics and in turn invent some elements whole-cloth (purefabrication).
The assignment is broken down into separate features. These features are:
1. SET-MY-CIRCUIT
2. GET-MY-INPUTS
3. RUN-MY-CIRCUIT
4. ADD-MY-MIRRORS
The features above are marked purely on automatic test cases.
There is then a separate part for testing Testing (Manually Graded) . This is instead manually
marked, in which the marker will mark your tests (both documentation and implementation) and
code style.
Marks
As discussed in Introduction , there is a marking proportion for each feature. These are marked
purely on the automatic test cases. These are the marking proportions below.
This sums up to a total of 20 marks.
The remaining 10 marks go towards the testing component which is manually graded. You can find
the section here Testing (Manually Graded) .
Summary of Features
This assignment will involve implementing each feature one-by-one. Each feature involves
implementing a set number of functions and classes which will be used in our program. Each feature
is separate, meaning adding a new feature does not require any changes to your existing features to
incorporate. In addition, when running the program, the user can specify which features they want
ran in their program, meaning not necessarily every feature needs to be used. As example, we could
create a circuit from inputs with mirrors added into it (Feature 1, 2 and 4), but not want to run it
(Feature 3). This creates a very flexible and modular program that is easy to extend.
1. SET-MY-CIRCUIT
SET-MY-CIRCUIT will focus on implementing the necessities to setup a circuit. A circuit comprises of
a board in which we can place components on it. Components include emitters (lasers that emits
photons) labelled from A to J and receivers (photodetectors that absorb photons) labelled from
R0 to R9 . We do not yet implement the circuitry functionalities.
By the end of this feature, you will be able to setup a circuit and display it to the user. An example is
we could setup a circuit with some fixed values; a board of size 18x6 characters, with two emitters A
and B and two receivers R0 and R1 (receivers are displayed by their number). We should then be
able to display it such as below.
+------------------+
| |
| B |
| A 0 |
| |
| 1 |
| |
+------------------+
2. GET-MY-INPUTS
GET-MY-INPUTS allows the user to specify what circuit they want to setup by providing inputs to the
program. From this, the user can setup a circuit to their own specifications.
Below is an example of how a user will setup their circuit.
We prepended the inputs with a # symbol so you can clearly see what the inputs to the program are.
$ python3 run.py
Creating circuit board...
> #18 6
18x6 board created.
Adding emitter(s)...
> #A 2 2
> #B 8 1
> #END EMITTERS
2 emitter(s) added.
Adding receiver(s)...
> #R0 15 2
> #R1 8 4
> #END RECEIVERS
2 receiver(s) added.
+------------------+
| |
| B |
| A 0 |
| |
| 1 |
| |
+------------------+
It will first ask to get the size of the board. The size is given in the format <width> <height> . The
example above creates a circuit board of size 18x6 .
It will then ask to add emitters on the board. The emitters are given in the format <symbol> <x> <y> .
Users can add up to 10 emitters, where each emitter is uniquely labelled from A to J . The example
above adds emitter A at position (2, 2) , followed by emitter B at position (8, 1) . Once users are
done adding emitters, they enter END EMITTERS to move on with the program.
Similarly, it will then ask to add receivers on the board. Users can add up to 10 receivers, where each
receiver is uniquely labelled from R0 to R9 . The example above adds receiver R0 at position (15,
2) then R1 at position (8, 4) . The user will be asked to keep adding receivers until 10 are added.
Once users are done adding receivers, they enter END RECEIVERS to move on with the program. At
this point, the only part left to do is to display the board.
By the end of this feature, you will have a run program that will be able to setup a circuit based on
the user's inputs and display the board.
3. RUN-MY-CIRCUIT
RUN-MY-CIRCUIT is responsible for running the circuit. The first step is that it reads from a file the
frequency and direction of each photon emitted. Each line of the file is in the format of <symbol>
<frequency> <direction> where <symbol> is the symbol of the emitter which will emit the photon,
<frequency> is the frequency of the photon and <direction> is the direction in which the photon
will travel.
This is called the pulse sequence. An example of a pulse_sequence.in file is shown below which is
located in /home/input/ .
A 100 E
B 256 S
The pulse sequence above defines that A will emit a photon at 100THz (terahertz) east and B will
emit a photon at 256THz south. After loading the pulse sequence into the circuit, the circuit performs
the following steps:
1. Each emitter emits a photon.
2. In each tick (a tick is a nanosecond), each photon moves. If a photon reaches a receiver, the
receiver will absorb the photon.
3. After each tick, we increment our clock (a simple counter) which keeps track of how long our
circuit has run for.
4. Repeat Steps 2-3 until all photons have been absorbed.
Once a receiver absorbs a photon, the receiver becomes activated in which it's charged with the
photon's energy. An activated receiver can continue absorbing more photons.
Let's look at a small example of running a circuit.
+------------------+
| |
| B |
| A 0 |
| |
| 1 |
| |
+------------------+
With the given circuit, we load the pulse sequence defined above into it. Then, we provide some steps
below to show what happens from here.
At 0ns (nanoseconds), the circuit emits photons. A emits a 100THz photon which will move to the
east and B emits a 256THz photon which will move to the south. When emitting the photons, the
photons initially start inside the emitter (hence the diagram looks no different).
+------------------+
| |
| B |
| A 0 |
| |
| 1 |
| |
+------------------+
At 1ns, each photon moves one unit on the board at their given directions.
+------------------+
| |
| B |
| A. . 0 |
| |
| 1 |
| |
+------------------+
Similarly for 2ns, each photon moves one unit on the board. You can see that we draw the path each
photon takes. You can picture it as the board being made of sand, and each time the photon moves, it
leaves a footstep on the ground.
+------------------+
| |
| B |
| A.. . 0 |
| . |
| 1 |
| |
+------------------+
At 3ns, the photon emitted from B has reached R1 , hence has been absorbed by this receiver. R1 is
now activated.
+------------------+
| |
| B |
| A... . 0 |
| . |
| 1 |
| |
+------------------+
At 13ns, R0 is activated as it absorbs the photon emitted from A .
+------------------+
| |
| B |
| A............0 |
| . |
| 1 |
| |
+------------------+
Running the circuit is now completed as all photons have been absorbed.
By the end of this feature, you will have a run program that can optionally run a circuit given that a
-RUN-MY-CIRCUIT flag is included as an argument. If it is not there, it will not run the circuit. Below is
an example run through of the program.
We prepended the inputs with a # symbol so you can clearly see what the inputs to the program are.
$ python3 run.py -RUN-MY-CIRCUIT
Creating circuit board...
> #18 6
18x6 board created.
Adding emitter(s)...
> #A 2 2
> #B 8 1
> #END EMITTERS
2 emitter(s) added.
Adding receiver(s)...
> #R0 15 2
> #R1 8 4
> #END RECEIVERS
2 receiver(s) added.
+------------------+
| |
| B |
| A 0 |
| |
| 1 |
| |
+------------------+
<RUN-MY-CIRCUIT FLAG DETECTED!>
Setting pulse sequence...
-- (A, B)
Line 1: #A 100 E
-- (B)
Line 2: #B 256 S
Pulse sequence set.
========================
RUNNING CIRCUIT...
========================
0ns: Emitting photons.
A: 100THz, East
B: 256THz, South
5ns: 1/2 receiver(s) activated.
+------------------+
| |
| B |
| A...... 0 |
| . |
| 1 |
| |
+------------------+
10ns: 1/2 receiver(s) activated.
+------------------+
| |
| B |
| A.......... 0 |
| . |
| 1 |
| |
+------------------+
13ns: 2/2 receiver(s) activated.
+------------------+
| |
| B |
| A............0 |
| . |
| 1 |
| |
+------------------+
Activation times:
R1: 3ns
R0: 13ns
Total energy absorbed:
R1: 1.06eV (1)
R0: 0.41eV (1)
========================
CIRCUIT FINISHED!
========================
Here are a few notes about the output above:
When setting the pulse sequence, you may have noticed the lines -- (A, B) and -- (B) .
These are showing the remaining emitters to set the pulse sequence for after each input read
from the pulse_sequence.in file.
When running the circuit, the state of the board is printed every 5ns, along with how many
receivers have been activated. We print the circuit one last time when all photons have been
absorbed, which in this case is at 13ns.
The activation times are printed in ascending order. You can see R1 is first which was activated
at time 3ns. Next was R0 which was activated at 13ns.
Next, the total energy absorbed is printed in descending order. The energy absorbed is
displayed in electronvolts (eV) and the number following it is the number of photons absorbed
by the receiver. In this case, R1 stores 1.06eV and absorbed 1 photon. Similarly, R2 stores
0.41eV and absorbed 1 photon
You will find out how to convert THz to electronvolts (eV) in RUN-MY-CIRCUIT . For now, just know that
a higher frequency (THz) means a higher energy (eV).
4. ADD-MY-MIRRORS
ADD-MY-MIRRORS allows the user to add mirrors into the circuit. Mirrors are able to reflect photons
off its surface which changes the direction in which the photons travel. Mirrors are a component just
like emitters and receivers.
Mirrors are given in the format <symbol> <x> <y> , similar to emitters and receivers. There are 4
different types of mirrors which include / , , > and ^ . We won't go in the details for each mirror,
just know that it will reflect photons off it depending on both the type of mirror and the direction of
the photon. Below is an example valid input of a mirror.
2 5
This would create a mirror / and place it at position (2, 5) on the circuit board. Since mirrors
aren't uniquely labelled (you can have multiple mirrors with the same symbol), users can enter as
many mirrors as they want, as long as there is space for it. Once they are finished, they can stop
adding mirrors by entering END MIRRORS .
By the end of this feature, you will have a run program that can optionally include mirrors given that
the -ADD-MY-MIRRORS flag is included as an argument. If it is not there, it will not involve mirrors in
the program. Below is an example run through of the program.
We prepended the inputs with a # symbol so you can clearly see what the inputs to the program are.
$ python3 run.py -RUN-MY-CIRCUIT -ADD-MY-MIRRORS
Creating circuit board...
> #18 6
18x6 board created.
Adding emitter(s)...
> #A 2 2
> #B 8 1
> #END EMITTERS
2 emitter(s) added.
Adding receiver(s)...
> #R0 15 2
> #R1 8 4
> #END RECEIVERS
2 receiver(s) added.
<ADD-MY-MIRRORS FLAG DETECTED!>
Adding mirror(s)...
> # 2 5
> #^ 5 5
> #/ 5 4
> # 11 1
> #> 11 4
> #/ 15 4
> #END MIRRORS
6 mirror(s) added.
+------------------+
| |
| B |
| A 0 |
| |
| / 1 > / |
| ^ |
+------------------+
<RUN-MY-CIRCUIT FLAG DETECTED!>
Setting pulse sequence...
-- (A, B)
Line 1: #A 100 S
-- (B)
Line 2: #B 256 E
Pulse sequence set.
========================
RUNNING CIRCUIT...
========================
0ns: Emitting photons.
A: 100THz, South
B: 256THz, East
5ns: 0/2 receiver(s) activated.
+------------------+
| |
| B.. |
| A . 0 |
| . . |
| . / 1 > / |
| ..^ |
+------------------+
10ns: 1/2 receiver(s) activated.
+------------------+
| |
| B.. |
| A . 0 |
| . . |
| . /..1 >.../ |
| ..^ |
+------------------+
12ns: 2/2 receiver(s) activated.
+------------------+
| |
| B.. |
| A . 0 |
| . . . |
| . /..1 >.../ |
| ..^ |
+------------------+
Activation times:
R1: 10ns
R0: 12ns
Total energy absorbed:
R0: 1.06eV (1)
R1: 0.41eV (1)
========================
CIRCUIT FINISHED!
========================
SET-MY-CIRCUIT (5 marks)
Introduction
A circuit board is defined on a two dimensional plane.
+------------------+
| |
| |
| |
| |
| |
| |
+------------------+
Each circuit can have up to 10 emitters and 10 receivers. Photons are emitted from emitters A to J
which may be received by a receiver R0 to R9 . The receivers on the board are displayed by their
number.
+------------------+
| |
| B |
| A 0 |
| |
| 1 |
| |
+------------------+
We can see that the circuit board has size 18x6 . The size does not include the border around the
board.
These are the positions of the emitters and receivers. The top left corner has position (0, 0) .
A : (2, 2)
B : (8, 1)
R0 : (15, 2)
R1 : (8, 4)
This should be enough information to cover the context of this feature, but you can scout for
additional information in Assignment Breakdown under Section 1. SET-MY-CIRCUIT if needed.
Your Task
The SET-MY-CIRCUIT feature will allow you to setup a circuit board just like the example in the above
section. In an implementation perspective, you'll be able to make a LaserCircuit instance and add
your own Emitter and Receiver instances into it. You will also be able to output the board on the
screen.
In this feature, you will be adding implementation to the following:
Emitter class
Receiver class
BoardDisplayer class
LaserCircuit class
There may be some functionalities in these classes that will be skipped. It will be specified what you need to
implement for this feature.
1. Emitter
An Emitter instance represents a laser which emits a photon with a frequency (THz) and direction
(either right or downwards).
These are the instance attributes of an Emitter instance.
When initialising an Emitter instance, it is given a symbol from A to J which is how this emitter
will be shown on the board. The emitter is given an x and y position which is its position on the
board. At the start, frequency is 0 and direction is None . This is later set by the pulse sequence
once we get up to running the circuit, hence the reason why pulse_sequence_set also starts false.
component_type is a constant with value 'emitter' which acts as an identity string for all emitters.
These are the instance methods of an Emitter instance that you'll need to implement for this
feature.
2. Receiver
A Receiver instance represents a photodetector that charges up by absorbing photons. When a
receiver absorbs a photon, it becomes activated in which it is charged with the photon's energy. An
activated receiver can keep absorbing more photons to store more energy. A receiver stores
information about the number of photons it has absorbed, the total energy it is charged with and
when it was activated. The amount of energy a receiver is charged with directly corresponds to the
frequency of all photons it absorbs summed up.
These are the instance attributes of a Receiver instance.
When initialising a Receiver instance, it is given a symbol from R0 to R9 . The number ( 0 to 9 ) is
what will be used to show the receiver on the board. The receiver is given an x and y position which
is its position on the board. At the start, total_energy is 0.0, photons_absorbed is 0 as it starts with
no photons absorbed. Similarly, activated is false and activation_time is 0 as it must absorb a
photon to become activated. component_type is a constant with value 'receiver' which acts as an
identity string for all receivers.
These are the instance methods of a Receiver instance that you'll need to implement for this
feature.
3. BoardDisplayer
A BoardDisplayer instance is responsible for displaying the circuit board. It's considered a helper
class as it does not assist with the functionality of the circuit. Its only purpose is to store a list of list of
strings (2 dimensional list of strings) representing the board. Each time a component is added to the
circuit, the BoardDisplayer instance is updated to store the component's symbol in its assigned
position in the 2D list.
These are the instance attributes of a BoardDisplayer instance.
When initialising a BoardDisplayer instance, it is given a width and height which will then be
used to initialise an empty board of that size.
These are the instance methods of a BoardDisplayer instance that you'll need to implement for this
feature.
Below we will provide clarifications for some of the instance methods to implement.
3.1 create_board
The create_board method takes in a width and height and will create a list of list of strings
representing an empty board of size width x height . As example, let's say width is 6 and height
is 3. Then the function needs to return the following:
[
[' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ']
]
You can see it's one list containing 3 inner-lists, representing our height. These are the rows.
Each row contains 6 elements, representing the width. These are the columns. Each element is a
single space, representing an empty cell on the board.
In the BoardDisplayer constructor, the board instance attribute should be given the return value of the
create_board method.
3.2 add_component_to_board
The add_component_to_board method takes in a component and adds its symbol on the board at
its assigned position.
It shouldn't scare you that it can accept different types of components. They all have common properties, that
being their symbol , x and y value. Since every component has these attributes, it doesn't actually matter
what component is passed in, you can treat them all the same.
Let's take the empty board we just made, and say we call the add_component_to_board method
twice. In the first call, we passed an emitter with symbol A and position (3, 1) and in the second
call, we passed a receiver with symbol R9 and position (0, 2) . Then, the board attribute will now
look like this.
[
[' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', 'A', ' ', ' '],
['9', ' ', ' ', ' ', ' ', ' ']
]
A is at board[1][3] and R9 is at board[2][0] .
To access position (x, y) on the board, it is board[y][x] as the first index represents the row (height) and
the second index represents the column (width).
3.3 print_board
For print_board , it will translate the board attribute into output. Let's take the example above
where we just put in an emitter and a receiver. After calling the method, it would print the following:
+------+
| |
| A |
|9 |
+------+
You can see the border is not included in the size (it wraps around the board).
4. Laser Circuit
A LaserCircuit instance is responsible for storing all components of the circuit and handling the
computation of running the circuit. It's responsible for delegating tasks to the specific components
e.g. making each emitter emit a photon, getting each photon to move and interact with components,
etc. In general, this class is responsible for handling any task related to the circuit.
These are the instance attributes of a LaserCircuit instance.
When initialising a LaserCircuit instance, it is given a width and height used to create the
board_displayer . The laser circuit initially starts with 0 components, so the list of emitters ,
receivers and mirrors start empty. Similarly, the list of photons start empty as no photons have
been emitted. clock starts at 0, this will increment once we begin running the circuit.
These are the instance methods of a LaserCircuit instance that you'll need to implement for this
feature.
4.1 print_board
The print_board method is straightforward. We simply call the print_board method of
board_displayer . This is so when we have a LaserCircuit instance, we can easily print the board.
4.2 get_collided_emitter
The get_collided_emitter checks if entity has the same x and y value as any emitter in the
circuit and returns that emitter if there exists a collision, else it returns None . Remember that all
components and photons have an x and y value, so we shouldn't need to worry about what specific
entity was passed in to check the collision. This also applies for get_collided_receiver in the
context that we are checking receivers instead of emitters.
Below are more methods that need to be implemented for this feature.
4.3 add_emitter
For add_emitter , here are the error messages for the checks you must perform.
Note from the method description that if at any point an error occurs, you return False . As example, if the
emitter is out-of-bounds, after printing the error message you return False , meaning the remaining 2 checks
are skipped.
Below are more methods that need to be implemented for this feature.
4.4 add_receiver
Similarly, here are the error messages for the checks you must perform. They mostly borrow from
add_emitters .
Below are the remaining methods that need to be implemented for this feature.
Let's run through of an example of initialising a LaserCircuit instance, printing the board, then
adding some components and printing the board again. We show an example of each error message
that can occur when adding a component into the circuit.
The following is run in a Python interactive session.
>>> from emitter import Emitter
>>> from receiver import Receiver
>>> from laser_circuit import LaserCircuit
# create the circuit and print board
>>> circuit = LaserCircuit(18, 6)
>>> circuit.print_board() # should initially be empty board
+------------------+
| |
| |
| |
| |
| |
| |
+------------------+
# create our emitters
>>> e1 = Emitter('A', 2, 2)
>>> e2 = Emitter('B', 8, 1)
# make an extra emitter to show error
>>> e3 = Emitter('C', 8, 1)
# add the emitters and print the board
>>> circuit.add_emitter(e1)
>>> circuit.add_emitter(e2)
>>> circuit.add_emitter(e3)
Error: position (8, 1) is already taken by emitter 'B'
>>> circuit.print_board()
+------------------+
| |
| B |
| A |
| |
| |
| |
+------------------+
# create out receivers
>>> r1 = Receiver('R0', 15, 2)
>>> r2 = Receiver('R1', 8, 4)
# make extra receivers to show error
>>> r3 = Receiver('R1', 9, 0)
>>> r4 = Receiver('R1', 0, 13)
# add the receivers and print the board
>>> circuit.add_receiver(r1)
>>> circuit.add_receiver(r2)
>>> circuit.add_receiver(r3)
Error: symbol 'R1' is already taken
>>> circuit.add_receiver(r4)
Error: position (0, 13) out-of-bounds on 18x6 circuit board
>>> circuit.print_board()
+------------------+
| |
| B |
| A 0 |
| |
| 1 |
| |
+------------------+
GET-MY-INPUTS (5 marks)
Introduction
In SET-MY-CIRCUIT , we implemented some classes to provide the base for building our circuit. Now
we want to allow the user to provide inputs to the program in which they will be able to create a
circuit to their own specifications.
On top of what's covered on Assignment Breakdown under Section 2. GET-MY-INPUTS , we will also
be covering input parsing. By this, we mean when users enter any input, whether it be for the board
size, emitters, or receivers, you will need to parse the input to validate that the input is correct.
An example of input parsing is shown below, where the user enters an incorrect size for the circuit
board multiple times.
Inputs are prepended with a # in the output snippets for your own clarity.
Creating circuit board...
> #18
Error: <width> <height>
> #18 six
Error: height must be an integer
> #18 6
18x6 board created.
Until the user enters a valid size, the program will keep asking for input. You can see entering only the
width displayed an error message Error: <width> <height> . The program then asked for input
again, in which the user incorrectly entered the height, displaying an error message Error: height
must be an integer . On the third input, the user entered a valid size, creating the board where the
program can proceed.
This is just a small look at the input parsing, there will be more to cover.
Your Task
The GET-MY-INPUTS feature will allow the user to set up a circuit to their specifications using inputs.
From an implementation perspective, you'll be making a LaserCircuit instance and adding
Emitter and Receiver instances into it based on the user's inputs. Then, you'll display the circuit
board to the user.
In this feature, you will be adding implementation to the following:
input_parser module
run module
There may be some functionalities in these modules that will be skipped. It will be specified what you need to
implement for this feature.
1. Input Parser
The input_parser module is responsible for parsing the inputs of the program. We define parsing as
checking the validity of what has been entered to determine if it's valid. If it's not valid, an appropriate
error message should be printed to indicate what was wrong with the input. Whenever we retrieve
input in the program, we should be using functions from this module to validate it.
These are the functions in the input_parser module that you'll need to implement for this feature.
1.1 parse_size
For parse_size , here are the error messages for the checks you must perform.
Note from the method description that if at any point an error occurs, you return None . As example, if the first
check passes but the second check fails (where width is not an integer), we return None , meaning the
remaining 3 checks are skipped.
Here are some examples of running parse_size in a Python interactive session.
Output Snippet 1 - Calling parse_size in a Python interactive session.
>>> from input_parser import parse_size
# Error 1
>>> size = parse_size('6')
Error: <width> <height>
>>> size
None
# Error 2
>>> size = parse_size('six 3')
Error: width is not an integer
>>> size
None
# Error 3
# Note: width is not positive (Error 4), however Error 3 is checked first
>>> size = parse_size('-6 three')
Error: height is not an integer
>>> size
None
# Error: 4
# Note: height is not positive (Error 5), however Error 4 is checked first
>>> size = parse_size('-6 -3')
Error: width must be greater than 0
>>> size
None
# Error 5
>>> size = parse_size('6 0')
Error: height must be greater than 0
>>> size
None
# No errors
>>> size = parse_size('6 3')
>>> size
(6, 3)
Below are more methods that need to be implemented for this feature.
1.2 parse_emitter
For parse_emitter , here are the error messages for the checks you must perform.
The checks and error messages are identical for parse_receiver , with the only exception being when
checking the symbol. Instead of A to J , we need to check from R0 to R9 ,. and the error message would be
Error: symbol is not between R0-R9 .
Here are some examples of running parse_emitter in a Python interactive session.
Output Snippet 2 - Calling parse_emitters in a Python interactive session.
>>> from input_parser import parse_emitter
# Error 1
>>> emitter = parse_emitter('A 0')
Error: <symbol> <x> <y>
>>> emitter
None
# Error 2
>>> emitter = parse_emitter('K 0 0')
Error: symbol is not between 'A'-'J'
>>> emitter
None
# Error 3
# Note: y is not an integer (Error 4), however Error 3 is checked first
>>> emitter = parse_emitter('A B C')
Error: x is not an integer
>>> emitter
None
# Error 4
>>> emitter = parse_emitter('A 0 zero')
Error: y is not an integer
>>> emitter
None
# Error 5
>>> emitter = parse_emitter('A -1 0')
Error: x cannot be negative
>>> emitter
None
# Error 6
>>> emitter = parse_emitter('A 0 -3')
Error: y cannot be negative
>>> emitter
None
# No errors
>>> emitter = parse_emitter('A 0 0')
>>> emitter
<Object: Emitter> # an emitter instance, just shown as this for readability
请加QQ:99515681 邮箱:99515681@qq.com WX:codinghelp