Skip to content

Commit 2e6afb8

Browse files
authored
add matrix exercise (#303)
by: oxe-i <[email protected]>
1 parent 4056609 commit 2e6afb8

File tree

12 files changed

+3841
-0
lines changed

12 files changed

+3841
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,14 @@
429429
"structs"
430430
]
431431
},
432+
{
433+
"slug": "matrix",
434+
"name": "Matrix",
435+
"uuid": "0c830b67-80b8-447a-a86d-22775e7d5ce4",
436+
"practices": [],
437+
"prerequisites": [],
438+
"difficulty": 4
439+
},
432440
{
433441
"slug": "phone-number",
434442
"name": "Phone Number",
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Instructions
2+
3+
Given a string representing a matrix of numbers, return the rows and columns of that matrix.
4+
5+
So given a string with embedded newlines like:
6+
7+
```text
8+
9 8 7
9+
5 3 2
10+
6 6 7
11+
```
12+
13+
representing this matrix:
14+
15+
```text
16+
1 2 3
17+
|---------
18+
1 | 9 8 7
19+
2 | 5 3 2
20+
3 | 6 6 7
21+
```
22+
23+
your code should be able to spit out:
24+
25+
- A list of the rows, reading each row left-to-right while moving top-to-bottom across the rows,
26+
- A list of the columns, reading each column top-to-bottom while moving from left-to-right.
27+
28+
The rows for our example matrix:
29+
30+
- 9, 8, 7
31+
- 5, 3, 2
32+
- 6, 6, 7
33+
34+
And its columns:
35+
36+
- 9, 5, 6
37+
- 8, 3, 6
38+
- 7, 2, 7
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"oxe-i"
4+
],
5+
"files": {
6+
"solution": [
7+
"matrix.asm"
8+
],
9+
"test": [
10+
"matrix_test.c"
11+
],
12+
"example": [
13+
".meta/example.asm"
14+
]
15+
},
16+
"blurb": "Given a string representing a matrix of numbers, return the rows and columns of that matrix.",
17+
"source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.",
18+
"source_url": "https://turing.edu"
19+
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
section .text
2+
global row
3+
global column
4+
5+
%macro store_num 0
6+
inc r8 ; increments counter
7+
8+
mov eax, r10d ; eax now holds number
9+
10+
xor rdx, rdx
11+
mov r10d, 10
12+
div r10d ; divide by 10 to account for an extra multiplication in accumulating loop
13+
14+
cmp r9b, 1
15+
jne %%store_num ; if sign flag is not set, proceed with storing it
16+
; otherwise negate num before storing it
17+
18+
neg eax
19+
20+
%%store_num:
21+
stosd ; store number in buffer
22+
%endmacro
23+
24+
; size_t row(int32_t *buffer, const char *input, size_t index);
25+
row:
26+
; rdi - output int32_t buffer
27+
; rsi - input string
28+
; rdx - index from the row to be extracted as a uint64_t
29+
; return is the size of buffer in rax
30+
31+
; The algorithm is:
32+
;
33+
; The input string is looped over until rdx is 1.
34+
; Each newline marks the end of a row and decreases rdx by 1.
35+
;
36+
; Then the desired row is looped over and each number is accumulated in r10.
37+
; Each space marks the end of a num
38+
; and a newline or a NULL marks the end of the entire row.
39+
;
40+
; At the beginning of each number, there's a check for the sign char.
41+
;
42+
; At the end of each number and of the row, the accumulator is adjusted for sign
43+
; and divided by 10 to account for an extra multiplication in the loop
44+
; then it's stored in the output buffer.
45+
; There's also a counter for the numbers, for returning at the end.
46+
;
47+
; If it's not the end of the row, the loop continues
48+
; It it is, the counter is moved to rax
49+
50+
xor r8, r8 ; counter
51+
.row_main_loop:
52+
cmp rdx, 1 ; matrix is 1-indexed
53+
je .row_copy ; found desired row
54+
55+
.find_next_row:
56+
lodsb
57+
58+
cmp al, 10 ; newline
59+
jne .find_next_row
60+
61+
dec rdx ; one row less
62+
jmp .row_main_loop
63+
64+
.row_copy:
65+
xor r9, r9
66+
xor r10, r10 ; accumulator for the number
67+
xor rax, rax
68+
.check_sign:
69+
lodsb
70+
cmp al, '-'
71+
sete r9b ; sign flag
72+
je .prepare_next_iteration
73+
.row_copy_loop:
74+
cmp al, 10
75+
je .end_copy ; newline marks end of the row
76+
77+
cmp al, 0
78+
je .end_copy ; NULL marks end of the row
79+
80+
cmp al, ' '
81+
je .end_num ; space marks end of the num
82+
; otherwise the number continues
83+
84+
sub al, '0' ; fromEnum
85+
86+
add r10, rax ; accumulates
87+
imul r10, r10, 10 ; multiplies by 10 to accumulate in next iteration
88+
; accumulator must be adjusted for an extra multiplication at the end
89+
90+
.prepare_next_iteration:
91+
lodsb
92+
jmp .row_copy_loop
93+
94+
.end_num:
95+
store_num ; macro
96+
jmp .row_copy
97+
98+
.end_copy:
99+
store_num ; macro
100+
mov rax, r8 ; moves counter to rax for returning
101+
102+
ret
103+
104+
; size_t column(int32_t *buffer, const char *input, size_t index);
105+
column:
106+
; rdi - output int32_t buffer
107+
; rsi - input string
108+
; rdx - index from the column to be extracted as a uint64_t
109+
; return is the size of buffer in rax
110+
111+
; The algorithm is:
112+
; The input string is looped over until rdx is 1, which marks the desired column.
113+
;
114+
; As this process is repeated for each new element, rdx is saved in r11 beforehand.
115+
;
116+
; Each space marks the end of a number and decreases rdx by 1,
117+
; the NULL char marks the end of the string and returns the function.
118+
;
119+
; Once found the element in the desired column, it's looped over and accumulated in r10.
120+
; At the beginning of each number, there's a check for the sign char.
121+
;
122+
; At the end of each number, the accumulator is adjusted for sign
123+
; and divided by 10 to account for an extra multiplication in the loop
124+
; then it's stored in the output buffer.
125+
; There's also a counter for the numbers, for returning at the end.
126+
;
127+
; A space, a newline or NULL marks the end of a number.
128+
; In case of a NULL, the number is stored and the function returns right away.
129+
; In the other cases, the number is stored and rdx is restored to loop over the input string
130+
; in search of the next desired element.
131+
132+
xor r8, r8 ; counter
133+
mov r11, rdx
134+
.column_main_loop:
135+
cmp rdx, 1 ; matrix is 1-indexed
136+
je .elem_copy ; found desired column
137+
138+
.find_next_elem:
139+
lodsb
140+
141+
cmp al, 0
142+
je .return ; NULL marks end of input and function returns right away
143+
144+
cmp al, ' ' ; num separator
145+
jne .find_next_elem
146+
147+
dec rdx ; decreases counter until desired column
148+
jmp .column_main_loop
149+
150+
.elem_copy:
151+
xor r10, r10 ; accumulator for the number
152+
xor rax, rax
153+
.check_sign:
154+
lodsb
155+
cmp al, '-'
156+
sete r9b ; sign flag
157+
je .prepare_next_iteration
158+
.elem_copy_loop:
159+
cmp al, 10
160+
je .end_num ; newline marks end of the number
161+
162+
cmp al, ' '
163+
je .end_num ; space marks end of the number
164+
165+
cmp al, 0
166+
je .end_copy ; NULL marks end of the string
167+
168+
sub al, '0' ; fromEnum
169+
170+
add r10, rax ; accumulates
171+
imul r10, r10, 10 ; multiplies by 10 to accumulate in next iteration
172+
; accumulator must be adjusted for an extra multiplication at the end
173+
174+
.prepare_next_iteration:
175+
lodsb
176+
jmp .elem_copy_loop
177+
178+
.end_num:
179+
; here it's end of current number, but not of the string
180+
181+
store_num ; macro
182+
183+
mov rdx, r11 ; as the string doesn't end here, there might be another row
184+
jmp .column_main_loop
185+
186+
.end_copy:
187+
; here it's end of the number and of the input string
188+
; so the number must be stored and the function should return soon after
189+
190+
store_num ; macro
191+
192+
.return:
193+
mov rax, r8 ; moves counter to rax for returning
194+
195+
ret
196+
197+
%ifidn __OUTPUT_FORMAT__,elf64
198+
section .note.GNU-stack noalloc noexec nowrite progbits
199+
%endif
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[ca733dab-9d85-4065-9ef6-a880a951dafd]
13+
description = "extract row from one number matrix"
14+
15+
[5c93ec93-80e1-4268-9fc2-63bc7d23385c]
16+
description = "can extract row"
17+
18+
[2f1aad89-ad0f-4bd2-9919-99a8bff0305a]
19+
description = "extract row where numbers have different widths"
20+
21+
[68f7f6ba-57e2-4e87-82d0-ad09889b5204]
22+
description = "can extract row from non-square matrix with no corresponding column"
23+
24+
[e8c74391-c93b-4aed-8bfe-f3c9beb89ebb]
25+
description = "extract column from one number matrix"
26+
27+
[7136bdbd-b3dc-48c4-a10c-8230976d3727]
28+
description = "can extract column"
29+
30+
[ad64f8d7-bba6-4182-8adf-0c14de3d0eca]
31+
description = "can extract column from non-square matrix with no corresponding row"
32+
33+
[9eddfa5c-8474-440e-ae0a-f018c2a0dd89]
34+
description = "extract column where numbers have different widths"

exercises/practice/matrix/Makefile

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
AS = nasm
2+
3+
CFLAGS = -g -Wall -Wextra -pedantic -Werror -std=c2x -Wno-gnu-binary-literal
4+
LDFLAGS =
5+
ASFLAGS = -g -F dwarf -Werror
6+
7+
ifeq ($(shell uname -s),Darwin)
8+
ifeq ($(shell sysctl -n hw.optional.arm64 2>/dev/null),1)
9+
ALL_CFLAGS = -target x86_64-apple-darwin
10+
endif
11+
ALL_LDFLAGS = -Wl,-pie
12+
ALL_ASFLAGS = -f macho64 --prefix _
13+
else
14+
ALL_LDFLAGS = -pie -Wl,--fatal-warnings
15+
ALL_ASFLAGS = -f elf64
16+
endif
17+
18+
ALL_CFLAGS += -std=c99 -fPIE -m64 $(CFLAGS)
19+
ALL_LDFLAGS += $(LDFLAGS)
20+
ALL_ASFLAGS += $(ASFLAGS)
21+
22+
C_OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
23+
AS_OBJS = $(patsubst %.asm,%.o,$(wildcard *.asm))
24+
ALL_OBJS = $(filter-out example.o,$(C_OBJS) $(AS_OBJS) vendor/unity.o)
25+
26+
CC_CMD = $(CC) $(ALL_CFLAGS) -c -o $@ $<
27+
28+
all: tests
29+
@./$<
30+
31+
tests: $(ALL_OBJS)
32+
@$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $(ALL_OBJS)
33+
34+
%.o: %.asm
35+
@$(AS) $(ALL_ASFLAGS) -o $@ $<
36+
37+
%.o: %.c
38+
@$(CC_CMD)
39+
40+
vendor/unity.o: vendor/unity.c vendor/unity.h vendor/unity_internals.h
41+
@$(CC_CMD)
42+
43+
clean:
44+
@rm -f *.o vendor/*.o tests
45+
46+
.PHONY: all clean

exercises/practice/matrix/matrix.asm

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
section .text
2+
global row
3+
global column
4+
5+
row:
6+
; Provide your implementation here
7+
ret
8+
9+
column:
10+
; Provide your implementation here
11+
ret
12+
13+
%ifidn __OUTPUT_FORMAT__,elf64
14+
section .note.GNU-stack noalloc noexec nowrite progbits
15+
%endif

0 commit comments

Comments
 (0)