Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add space-age exercise #258

Merged
merged 4 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@
"prerequisites": [],
"difficulty": 4
},
{
"slug": "space-age",
"name": "Space Age",
"uuid": "24c7e0dc-6c3e-405e-8449-c8da0100545d",
"practices": [],
"prerequisites": [],
"difficulty": 4
},
{
"slug": "atbash-cipher",
"name": "Atbash Cipher",
Expand Down
6 changes: 6 additions & 0 deletions exercises/practice/space-age/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Hints

## General

- The `$t0-9` registers can be used to temporarily store values
- The instructions specify which registers are used as input and output
16 changes: 16 additions & 0 deletions exercises/practice/space-age/.docs/instructions.append.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Instructions append

## Output format

Output the age in hundredths of a year.
keiravillekode marked this conversation as resolved.
Show resolved Hide resolved

For example, 100 × 1,000,000,000 ÷ 31,557,600 ≈ 3,169, so someone 1,000,000,000 seconds old is `3169` hundredths of an Earth-year old.

## Registers

| Register | Usage | Type | Description |
| -------- | --------- | ------- | ----------------------------- |
| `$a0` | input | integer | planet (`0` = Mercury, `1` = Venus, `2` = Earth, `3` = Mars, `4` = Jupiter, `5` = Saturn, `6` = Uranus, `7` = Neptune) |
| `$a1` | input | integer | seconds |
| `$v0` | output | integer | age in hundredths of a year |
| `$t0-9` | temporary | any | used for temporary storage |
28 changes: 28 additions & 0 deletions exercises/practice/space-age/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Instructions

Given an age in seconds, calculate how old someone would be on a planet in our Solar System.

One Earth year equals 365.25 Earth days, or 31,557,600 seconds.
If you were told someone was 1,000,000,000 seconds old, their age would be 31.69 Earth-years.

For the other planets, you have to account for their orbital period in Earth Years:

| Planet | Orbital period in Earth Years |
| ------- | ----------------------------- |
| Mercury | 0.2408467 |
| Venus | 0.61519726 |
| Earth | 1.0 |
| Mars | 1.8808158 |
| Jupiter | 11.862615 |
| Saturn | 29.447498 |
| Uranus | 84.016846 |
| Neptune | 164.79132 |

~~~~exercism/note
The actual length of one complete orbit of the Earth around the sun is closer to 365.256 days (1 sidereal year).
The Gregorian calendar has, on average, 365.2425 days.
While not entirely accurate, 365.25 is the value used in this exercise.
See [Year on Wikipedia][year] for more ways to measure a year.

[year]: https://en.wikipedia.org/wiki/Year#Summary
~~~~
20 changes: 20 additions & 0 deletions exercises/practice/space-age/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Introduction

The year is 2525 and you've just embarked on a journey to visit all planets in the Solar System (Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus and Neptune).
The first stop is Mercury, where customs require you to fill out a form (bureaucracy is apparently _not_ Earth-specific).
As you hand over the form to the customs officer, they scrutinize it and frown.
"Do you _really_ expect me to believe you're just 50 years old?
You must be closer to 200 years old!"

Amused, you wait for the customs officer to start laughing, but they appear to be dead serious.
You realize that you've entered your age in _Earth years_, but the officer expected it in _Mercury years_!
As Mercury's orbital period around the sun is significantly shorter than Earth, you're actually a lot older in Mercury years.
After some quick calculations, you're able to provide your age in Mercury Years.
The customs officer smiles, satisfied, and waves you through.
You make a mental note to pre-calculate your planet-specific age _before_ future customs checks, to avoid such mix-ups.

~~~~exercism/note
If you're wondering why Pluto didn't make the cut, go watch [this YouTube video][pluto-video].

[pluto-video]: https://www.youtube.com/watch?v=Z_2gbGXzFbs
~~~~
19 changes: 19 additions & 0 deletions exercises/practice/space-age/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"keiravillekode"
],
"files": {
"solution": [
"impl.mips"
],
"test": [
"runner.mips"
],
"example": [
".meta/example.mips"
]
},
"blurb": "Given an age in seconds, calculate how old someone is in terms of a given planet's solar years.",
"source": "Partially inspired by Chapter 1 in Chris Pine's online Learn to Program tutorial.",
"source_url": "https://pine.fm/LearnToProgram/?Chapter=01"
}
41 changes: 41 additions & 0 deletions exercises/practice/space-age/.meta/example.mips
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# | Register | Usage | Type | Description |
# | -------- | --------- | ------- | ------------------------------------------ |
# | `$a0` | input | integer | planet (`0` = Mercury, `1` = Venus, |
# | | | | `2` = Earth, `3` = Mars, `4` = Jupiter, |
# | | | | `5` = Saturn, `6` = Uranus, `7` = Neptune) |
# | `$a1` | input | integer | seconds |
# | `$v0` | output | integer | age in hundredths of a year |
# | `$t0` | temporary | address | address of reciprocal of planet's period |
# | `$t1` | temporary | integer | reciprocal of planet's period |
# | `$t2` | temporary | integer | 0x8000, used to round up result |

.globl age

.data

# reciprocal of the number of seconds in a year, scaled up by 100 * 2**48
reciprocals: .word
3703353120, # Mercury,
1449844523, # Venus,
891940378, # Earth,
474230585, # Mars,
75189187, # Jupiter,
30289174, # Saturn,
10616209, # Uranus,
5412545 # Neptune

.text

age:
la $t0, reciprocals
sll $a0, $a0, 2
add $t0, $t0, $a0
lw $t1, 0($t0) # load reciprocal of the number of seconds in a year
multu $t1, $a1
mfhi $v0 # scale down by 2**32 by discarding low bits

ori $t2, $zero, 0x8000
addu $v0, $v0, $t2 # scale down by 2**16, with rounding
srl $v0, $v0, 16

jr $ra
38 changes: 38 additions & 0 deletions exercises/practice/space-age/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[84f609af-5a91-4d68-90a3-9e32d8a5cd34]
description = "age on Earth"

[ca20c4e9-6054-458c-9312-79679ffab40b]
description = "age on Mercury"

[502c6529-fd1b-41d3-8fab-65e03082b024]
description = "age on Venus"

[9ceadf5e-a0d5-4388-9d40-2c459227ceb8]
description = "age on Mars"

[42927dc3-fe5e-4f76-a5b5-f737fc19bcde]
description = "age on Jupiter"

[8469b332-7837-4ada-b27c-00ee043ebcad]
description = "age on Saturn"

[999354c1-76f8-4bb5-a672-f317b6436743]
description = "age on Uranus"

[80096d30-a0d4-4449-903e-a381178355d8]
description = "age on Neptune"

[57b96e2a-1178-40b7-b34d-f3c9c34e4bf4]
description = "invalid planet causes error"
include = false
22 changes: 22 additions & 0 deletions exercises/practice/space-age/impl.mips
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# | Register | Usage | Type | Description |
# | -------- | --------- | ------- | ------------------------------------------ |
# | `$a0` | input | integer | planet (`0` = Mercury, `1` = Venus, |
# | | | | `2` = Earth, `3` = Mars, `4` = Jupiter, |
# | | | | `5` = Saturn, `6` = Uranus, `7` = Neptune) |
# | `$a1` | input | integer | seconds |
# | `$v0` | output | integer | age in hundredths of a year |
# | `$t0-9` | temporary | any | used for temporary storage |

.eqv MERCURY 0
.eqv VENUS 1
.eqv EARTH 2
.eqv MARS 3
.eqv JUPITER 4
.eqv SATURN 5
.eqv URANUS 6
.eqv NEPTUNE 7

.globl age

age:
jr $ra
123 changes: 123 additions & 0 deletions exercises/practice/space-age/runner.mips
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#
# Test age with some examples
#
# s0 - num of tests left to run
# s1 - address of planet input word
# s2 - address of seconds input word
# s3 - address of expected output word
# s4 - output word

.data
# number of test cases
n: .word 8
# input values (word sized ints)
planets: .word
2, # Earth,
0, # Mercury,
1, # Venus,
3, # Mars,
4, # Jupiter,
5, # Saturn,
6, # Uranus,
7 # Neptune
seconds: .word
1000000000,
2134835688,
189839836,
2129820540,
901876382,
2000000000,
1210792309,
1821023456
# output values (word sized ints)
outs: .word
3169,
28088,
978,
3588,
241,
215,
46,
35

failmsg: .asciiz "failed for test input: ("
commamsg: .asciiz ", "
expectedmsg: .asciiz "). expected "
tobemsg: .asciiz " to be "
okmsg: .asciiz "all tests passed"


.text

runner:
lw $s0, n
la $s1, planets
la $s2, seconds
la $s3, outs
j run_test

run_test:
lw $a0, 0($s1) # move input planet number to a0
lw $a1, 0($s2) # move input seconds number to a1
jal age # call subroutine under test
move $v1, $v0 # move return value in v0 to v1 because we need v0 for syscall

lw $s4, 0($s3) # read expected output from memory
bne $v1, $s4, exit_fail # if expected doesn't match actual, jump to fail

addi $s1, $s1, 4 # move to next planet word in input
addi $s2, $s2, 4 # move to next seconds word in input
addi $s3, $s3, 4 # move to next word in output

sub $s0, $s0, 1 # decrement num of tests left to run
bgt $s0, $zero, run_test # if more than zero tests to run, jump to run_test

exit_ok:
la $a0, okmsg # put address of okmsg into a0
li $v0, 4 # 4 is print string
syscall

li $v0, 10 # 10 is exit with zero status (clean exit)
syscall

exit_fail:
la $a0, failmsg # put address of failmsg into a0
li $v0, 4 # 4 is print string
syscall

lw $a0, ($s1) # print input that failed on
li $v0, 1
syscall

la $a0, commamsg
li $v0, 4
syscall

lw $a0, ($s2)
li $v0, 1
syscall

la $a0, expectedmsg
li $v0, 4
syscall

move $a0, $v1 # print actual that failed on
li $v0, 1
syscall

la $a0, tobemsg
li $v0, 4
syscall

move $a0, $s4 # print expected value that failed on
li $v0, 1
syscall

li $a0, 1 # set error code to 1
li $v0, 17 # 17 is exit with error
syscall

jr $ra

# # Include your implementation here if you wish to run this from the MARS GUI.
# .include "impl.mips"