Skip to content

Commit

Permalink
Add minesweeper exercise (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
keiravillekode authored Dec 6, 2024
1 parent dee22b5 commit 9d4cdc9
Show file tree
Hide file tree
Showing 16 changed files with 7,123 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,14 @@
"prerequisites": [],
"difficulty": 6
},
{
"slug": "minesweeper",
"name": "Minesweeper",
"uuid": "d5008701-7328-4115-a85b-93c950a96a29",
"practices": [],
"prerequisites": [],
"difficulty": 7
},
{
"slug": "pythagorean-triplet",
"name": "Pythagorean Triplet",
Expand Down
26 changes: 26 additions & 0 deletions exercises/practice/minesweeper/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Instructions

Your task is to add the mine counts to empty squares in a completed Minesweeper board.
The board itself is a rectangle composed of squares that are either empty (`' '`) or a mine (`'*'`).

For each empty square, count the number of mines adjacent to it (horizontally, vertically, diagonally).
If the empty square has no adjacent mines, leave it empty.
Otherwise replace it with the adjacent mines count.

For example, you may receive a 5 x 4 board like this (empty spaces are represented here with the '·' character for display on screen):

```text
·*·*·
··*··
··*··
·····
```

Which your code should transform into this:

```text
1*3*1
13*31
·2*2·
·111·
```
5 changes: 5 additions & 0 deletions exercises/practice/minesweeper/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Introduction

[Minesweeper][wikipedia] is a popular game where the user has to find the mines using numeric hints that indicate how many mines are directly adjacent (horizontally, vertically, diagonally) to a square.

[wikipedia]: https://en.wikipedia.org/wiki/Minesweeper_(video_game)
17 changes: 17 additions & 0 deletions exercises/practice/minesweeper/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"authors": [
"keiravillekode"
],
"files": {
"solution": [
"minesweeper.s"
],
"test": [
"minesweeper_test.c"
],
"example": [
".meta/example.s"
]
},
"blurb": "Add the numbers to a minesweeper board."
}
117 changes: 117 additions & 0 deletions exercises/practice/minesweeper/.meta/example.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
.text
.globl annotate

/*
# | Register | Usage | Type | Description |
# | -------- | ------------ | ------- | --------------------------------------------- |
# | `x0` | input/output | address | null-terminated output string |
# | `x1` | input | address | null-terminated input string |
# | `x2` | temporary | address | pointer into input |
# | `w3` | temporary | byte | input character |
# | `x4` | temporary | address | line length (including newline character) |
# | `x5` | temporary | address | location of input's null terminator |
# | `x6` | temporary | address | previous row (or current for first row) |
# | `x7` | temporary | address | current row |
# | `x8` | temporary | address | next row (or current for last row) |
# | `x9` | temporary | integer | previous column (or current for first column) |
# | `x10` | temporary | integer | current column |
# | `x11` | temporary | integer | next column (or current for last column) |
# | `x12` | temporary | address | row of adjacent square |
# | `x13` | temporary | integer | column of adjacent square |
# | `w14` | temporary | byte | newline character |
# | `w15` | temporary | integer | number of adjacent mines |
# | `w16` | temporary | byte | mine character '*' |
*/

/* extern void annotate(char *buffer, const char *minefield); */
annotate:
mov x2, x1
ldrb w3, [x2] /* read first byte of minefield */
cbz w3, .return

mov w16, #'*' /* mine character */
mov w14, #'\n'

.find_newline:
ldrb w3, [x2], #1
cmp w3, w14
bne .find_newline

sub x4, x2, x1 /* line length (including newline character) */
mov x2, x1

.find_null:
add x2, x2, x4 /* jump ahead by line length */
ldrb w3, [x2]
cbnz w3, .find_null

mov x5, x2 /* location of input's null terminator */
mov x7, x1
mov x8, x1 /* start of first row */

.next_row:
mov x10, xzr /* first column */
mov x11, xzr
mov x6, x7 /* current row becomes previous row */
mov x7, x8 /* next row becomes current row */

add x8, x7, x4 /* next row */
cmp x8, x5
bne .first_column

mov x8, x7 /* last row */

.first_column:
cmp x4, #1
beq .write_newline /* jump ahead if rows contain no squares */

.next_column:
mov x9, x10 /* current column becomes previous column */
mov x10, x11 /* next column becomes current column */
add x11, x10, #2
cmp x11, x4
cset x11, ne /* Set x11 to 1 if there are more columns, otherwise 0 */
add x11, x10, x11 /* next column */

ldrb w3, [x7, x10] /* minefield square */
cmp w3, w16
beq .write_square /* jump ahead if we have reached a mine */

mov w15, wzr /* number of adjacent mines */
sub x12, x6, x4

.adjacent_row:
add x12, x12, x4 /* address of adjacent row: x6, x6+x4, x8 */
sub x13, x9, #1

.adjacent_column:
add x13, x13, #1 /* index of adjacent column: x9, x9+1, x11 */

ldrb w3, [x12, x13] /* adjacent square */
cmp w3, w16
cset x2, eq /* 1 if square contains mine, 0 otherwise */
add w15, w15, w2 /* update mine count */
cmp x13, x11
bne .adjacent_column

cmp x12, x8
bne .adjacent_row

mov w3, #' '
cbz w15, .write_square

add w3, w15, #'0' /* mine count, as ASCII digit */

.write_square:
strb w3, [x0], #1
cmp x10, x11
bne .next_column

.write_newline:
strb w14, [x0], #1 /* write '\n' */
cmp x7, x8
bne .next_row

.return:
strb wzr, [x0] /* null terminator */
ret
46 changes: 46 additions & 0 deletions exercises/practice/minesweeper/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# 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.

[0c5ec4bd-dea7-4138-8651-1203e1cb9f44]
description = "no rows"

[650ac4c0-ad6b-4b41-acde-e4ea5852c3b8]
description = "no columns"

[6fbf8f6d-a03b-42c9-9a58-b489e9235478]
description = "no mines"

[61aff1c4-fb31-4078-acad-cd5f1e635655]
description = "minefield with only mines"

[84167147-c504-4896-85d7-246b01dea7c5]
description = "mine surrounded by spaces"

[cb878f35-43e3-4c9d-93d9-139012cccc4a]
description = "space surrounded by mines"

[7037f483-ddb4-4b35-b005-0d0f4ef4606f]
description = "horizontal line"

[e359820f-bb8b-4eda-8762-47b64dba30a6]
description = "horizontal line, mines at edges"

[c5198b50-804f-47e9-ae02-c3b42f7ce3ab]
description = "vertical line"

[0c79a64d-703d-4660-9e90-5adfa5408939]
description = "vertical line, mines at edges"

[4b098563-b7f3-401c-97c6-79dd1b708f34]
description = "cross"

[04a260f1-b40a-4e89-839e-8dd8525abe0e]
description = "large minefield"
36 changes: 36 additions & 0 deletions exercises/practice/minesweeper/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
AS = aarch64-linux-gnu-as
CC = aarch64-linux-gnu-gcc

CFLAGS = -g -Wall -Wextra -pedantic -Werror
LDFLAGS =

ALL_LDFLAGS = -pie -Wl,--fatal-warnings

ALL_CFLAGS = -std=c99 -fPIE $(CFLAGS)
ALL_LDFLAGS += $(LDFLAGS)

C_OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
AS_OBJS = $(patsubst %.s,%.o,$(wildcard *.s))
ALL_OBJS = $(filter-out example.o,$(C_OBJS) $(AS_OBJS) vendor/unity.o)

CC_CMD = $(CC) $(ALL_CFLAGS) -c -o $@ $<

all: tests
qemu-aarch64 -L /usr/aarch64-linux-gnu ./$<

tests: $(ALL_OBJS)
@$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $(ALL_OBJS)

%.o: %.s
@$(AS) -o $@ $<

%.o: %.c
@$(CC_CMD)

vendor/unity.o: vendor/unity.c vendor/unity.h vendor/unity_internals.h
@$(CC_CMD)

clean:
@rm -f *.o vendor/*.o tests

.PHONY: all clean
5 changes: 5 additions & 0 deletions exercises/practice/minesweeper/minesweeper.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.text
.globl annotate

annotate:
ret
Loading

0 comments on commit 9d4cdc9

Please sign in to comment.