Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
honors project 1 and merge sort
  • Loading branch information
Jerry Shi committed Feb 2, 2024
1 parent 9a9d5a7 commit a129644
Show file tree
Hide file tree
Showing 5 changed files with 335 additions and 0 deletions.
35 changes: 35 additions & 0 deletions extra/merge-sort/README.md
@@ -0,0 +1,35 @@
# Mergesort

Here is a skeleton code for merge sort.

The pseudocode for merge sort function is in a homework question. It
needs minor changes if we want to support large arrays.

The pseudocode for `array_merge` is below. This version uses a single loop and
does not need `array_copy` function.


```C
// Merge sorted two arrays a1 and a2 into one array dst
void array_merge(int dst[], int a1[], int n1, int a2[], int n2)
{
int total = n1 + n2;

// we maintain three indexes, one for each array
int i1 = i2 = id = 0;

while (id < total) {
if ((i2 >= n2) || (i1 < n1 && a1[i1] < a2[i2])) {
// Note that if i1 >= n1, control flow goes to the ELSE branch
// copy an element from a1 to dst
dst[id] = a1[i1];
i1 += 1;
} else {
// copy an element from a2 to dst
dst[id] = a2[i2];
i2 += 1;
}
id += 1;
}
}
```
77 changes: 77 additions & 0 deletions extra/merge-sort/mergesort.s
@@ -0,0 +1,77 @@
# Merge Sort

.data #data segment
.align 2
buffer: .space 4096 #allocate space for 1K words

.text # Code segment
.globl main # declare main to be global
main:
# specify the size of the array, must be less than 1024
# la s1, buffer # address of the buffer
lui s1, 0x10010 # hard code the address
addi s2, x0, 200 # number of elements

# call init_array() to initialize the array with random values
addi a0, s1, 0
addi a1, s2, 0
jal ra, init_array

# call merge_sort function with proper arguments
# we must assume a0 and a1 are changed after function call
addi a0, s1, 0
addi a1, s2, 0
jal ra, merge_sort

# set a breakpoint here and examine the memory
Exit:
addi a7, x0, 10
ecall

# void init_array(int p[], int n)
# use pseudorandom numbers to fill out the array
init_array:
# we use pointers in this function
# t0 is the starting address and
# t1 is the word address right after the array
addi t0, a0, 0
slli t1, a1, 2
add t1, t1, t0 # &p[n]

# set the seed
addi a0, x0, 0
lui a1, 0x3666
addi a7, x0, 40
ecall

# syscall for rand()
# 41 on randon integer
# 42 for bounded values. upper bound is in a1
# a1 and a7 are not changed in the loop
lui a1, 0x100
addi a7, x0, 42

beq zero, zero, ia_test
ia_loop:
addi a0, x0, 0
ecall # a1 and a7 are set before the loop
sw a0, 0(t0) # save the random value
addi t0, t0, 4 # move to the next word
ia_test:
bltu t0, t1, ia_loop

jalr x0, ra, 0

####START_OF_MERGE_SORT and helper functions

# array_merge(int da[], int a1[], int n1, int a2[], int n2)
# merge sorted array a1 and a2 into array da
# a1 has n1 words and a2 has n2 words
array_merge:


# void merge_sort(int p[], int n)
# TODO
merge_sort:


106 changes: 106 additions & 0 deletions honors/eightqueens/eightqueens.c
@@ -0,0 +1,106 @@
#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0
#define BOARDSIZE 8
#define EMPTY_CHAR '-'


int difference(int i, int j)
{
if (i < j)
return j - i;
else
return i - j;
}

int is_valid(int a[], int row, int column)
{
// check if any queen already placed threats board[row][column]
for (int i = 0; i < row; i ++) {
if ((column == a[i]) // column threat
|| difference(i, row) == difference(a[i], column)) // diagonal threat
return FALSE;
}
return TRUE;
}

void my_puts(int *s)
{
int i;

for (i = 0; s[i]; i ++)
putchar(s[i]);
putchar('\n');
}

void process_solution(int a[], int k)
{
// print the board
int line[BOARDSIZE + 1];

for (int i = 0; i < BOARDSIZE; i ++) {
line[i] = EMPTY_CHAR;
}
line[BOARDSIZE] = 0;

for (int i = 0; i < BOARDSIZE; i ++) {
line[a[i]] = '*';
my_puts(line);
line[a[i]] = EMPTY_CHAR;
}

// no need to print the numbers in assembly code
for (int i = 0; i < BOARDSIZE; i ++) {
printf("%d ", a[i]);
}
putchar('\n');
}


// k: number of queens already placed and k >= 0
int solve_8queens(int a[], int k)
{
int counter = 0;

if (k == BOARDSIZE) {
// if all queens have already been placed ...
process_solution(a, k);
counter += 1;
}
else {
// try row k. Rows 0 .. (k-1) already have a queen
// Use j for columns
for (int j = 0; j < BOARDSIZE; j ++) {
if (is_valid(a, k, j)) {
a[k] = j;
counter += solve_8queens(a, k+1);
if (counter ) {
// terminate after the first solution
break;
}
}
}
}
return counter;
}

int main(int argc, char **argv)
{
int a[BOARDSIZE] = {0}; /* location of queens. */

if (argc == 2) {
int c = atoi(argv[1]);
if (c < 0 || c >= BOARDSIZE) {
printf("The position is not correct.\n");
return -1;
}
a[0] = c;
}

// int solution_counts[]={1, 0, 0, 2, 10, 4, 40, 92};

printf("Number of solutions=%d\n", solve_8queens(a, 1));
return 0;
}
70 changes: 70 additions & 0 deletions honors/eightqueens/eightqueens.md
@@ -0,0 +1,70 @@
# Eight Queens

Deadline: demo by Friday, 03/01/2024. Come to professors' office hours or make
an appointment with Prof Shi or Prof Ding.

The eight queens problem is a classic coding problem. The goal is to place
eight chess queens on an 8×8 chessboard and no two queens threaten each
other. The size of board may be adjusted.

In this assignment, we write a RISC-V program to find a solution on an 8x8
board, when the location of the queen in the first row (row 0) is specified.
One implementation in C is in "eightqueens.c". In this version, the program
stops searching when the first solution is found. The location of the first
queen defaults to column 0, but it can be specified at the command line. For
example, the following command place the frist queen in row 0, column 1.

./eightqueens 1

The skeleton code is in "eightqueens.s". Here are some differences in the
assembly verson and some constraints.

* Assume only two branch instructions, BEQ and BNE, are available. Do not use
BLT, BGE, BLTU, or BGEU. Otherwise, you will have to rewirte your code
later.

* The location of the queen in row 0 is specifed by the first number in array
`a`. We can change the number manually. Note that array `a` is on the
stack.

* In function `process_solution()`, there is no need to write the second loop
to print decimal values. Once the program terminates, we can see the numbers
in array `a` in data segment window.

Also, pay attention to `line`. It is a local word array.

`my_puts` function is provided in the skeleton code.

## Testing

The solutions found by the RISC-V program should be the same as the ones found
by the C program. Here are some solutions from the C program. Note that the
number of solutions is 1 because we terminate the search when the first
solution is found. Compile the C program and compare the results for other
initial setups.

```
# ./eightqueens
*-------
----*---
-------*
-----*--
--*-----
------*-
-*------
---*----
0 4 7 5 2 6 1 3
Number of solutions=1
# ./eightqueens 1
-*------
---*----
-----*--
-------*
--*-----
*-------
------*-
----*---
1 3 5 7 2 0 6 4
Number of solutions=1
```
47 changes: 47 additions & 0 deletions honors/eightqueens/eightqueens.s
@@ -0,0 +1,47 @@
# code
.text
.globl main
main:

# allocate space for array a from the stack
# the numbers in the array are the location of the queen in each row.
# we can place the queen in row 0 in a different column
# by changing the first 0 below.

addi sp, sp, -32
addi a0, sp, 0 # put a's address in a0

addi t0, x0, 0 # place a queen in column 0 in row 0
sw t0, 0(a0)

addi a1, x0, 1 # number of queens already placed
jal ra, solve_8queens

beq x0, x0, exit

# print a string stored in a word array, and a newline
my_puts:
addi a7, x0, 11 # system call printing a character
addi t0, a0, 0 # copy a0 to t0, which is the address of the array
mp_loop:
lw a0, 0(t0)
beq a0, x0, mp_exit
ecall
addi t0, t0, 4
beq x0, x0, mp_loop
mp_exit:
# print newline
addi a0, x0, '\n'
ecall
jalr x0, ra, 0

#######################
### put your code here
solve_8queens:


### End of your code
#######################

exit:
# no need to do anything here

0 comments on commit a129644

Please sign in to comment.