/OS110_MediumExercism

This is an assignment of Operating System course in semester 110 of Jakarta State University's computer science courses, about completing medium level challenges in exercism.io's Rust track

Primary LanguageRust

.zip | .tar.gz

Github.io project page - parampaa2.github.io/OS110_MediumExercism

Muhammad Aufi Rayesa Frandhana Computer Science of Jakarta State University, 2017 Operating System course of 110th semester 1313617014 github.com/parampaa2

OS110_MediumExercism

This is an assignment of Operating System course in semester 110 of Jakarta State University's computer science courses, about completing medium level challenges in exercism.io's Rust track


I have chosen five completed medium exercism challenges as the submission for current assignment:

Also, I will describe on how i solved the Diamond problem.


Diamond

Snippet:

pub fn get_diamond(c: char) -> Vec<String> {
    let complete = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //Prepare the set of valid alphabets, in order
    let length = complete.chars().enumerate().map(|(i,x)|if x==c {1*i} else {0}).fold(0,|acc,x|acc+x)+1; //Find the char index in the valid alphabets string
    //let finlength = (2 * &length ) - 1; // This used to be a variable of my final diamond length, but since it is only used once i decide to get rid of it.
    let pivot = &length - 1; //I use this number to mark which place to print a char
    let used = complete[..length].chars().collect::<Vec<char>>(); //Vec of used chars, not the complete alphabet.
    let iterating = ((length as isize)-(((2 * &length ) - 1) as isize)..(length as isize)).map(|x|length-(x.abs() as usize)-1).collect::<Vec<usize>>(); //This is the array i will use in iteration
    let mut out: Vec<String> = Vec::new(); //Resulting string container
    for i in iterating.iter().cloned() { //Iterate through the iterating vec
        let mut line = String::new(); //Prepare current line printing
        for j in iterating.iter().cloned() { //Iterate through the iterating vec,again
            if &i+&j == pivot {line.push(used[i]);} //if sum of index i and j is same like pivot, then it's time to print char.
            else {line.push(' ');} //well if not, just a regular spacebar.
        }
        out.push(line); //At the end of the first level iteration, push the current line to container
    }
    out //Return the container as output
}

The problem

The goal was straightforward, we're only have to make strings that would look like this, specifically a diamond consisted of ordered chars, this is the example for character E 'diamond':

    A
   B B
  C   C
 D     D
E       E
 D     D
  C   C
   B B 
    A

Pre-coding analysis / problem solving

Without much thinking, i try to reinterpret the characters as numbers, starting from 0:

    0
   1 1
  2   2
 3     3
4       4
 3     3
  2   2
   1 1 
    0
    
hence, 'ABCDE' ~ '01234'
also mark that 4 is the maximum index we can get from it.

The diamonds has two symmetries that lies on the middle of both x and y axis through the relative center of the diamond object, which means we can divide the diamond into 4, almost similar, repeating pattern which look like this:

    0
   1
  2
 3
4

After revealing that, i try to make a grid that represents the position of each character:

\ 0 1 2 3 4
 +---------
0|        0
1|      1
2|    2
3|  3
4|4

Interesting enough, if we sum each of the element's x and y coordinate, we'll have the same number.

0 -> (0,4) -> 0 + 4 = 4

1 -> (1,3) -> 1 + 3 = 4

2 -> (2,2) -> 2 + 2 = 4

3 -> (3,1) -> 3 + 1 = 4

4 -> (4,0) -> 4 + 0 = 4

And from this point, i will refer to that 'same number' as pivot. From this, we can conclude the letters are only 'printed' if the sum of their coordinates matches with pivot. Then, to finish my analisis, i continue to use current interpretation to the whole diamond, not just the first fraction. That means i also apply the grid to the whole diamond, but instead of continuing the coordinate numbers following order, i will just mirror the coordinate after the pivot:

\ 0 1 2 3 4 3 2 1 0
 +-----------------
0|        0
1|      1   1
2|    2       2
3|  3           3
4|4               4
3|  3           3
2|    2       2
1|      1   1
0|        0

In a nutshell, these are the hints that so far we have revealed:

  • Alphabets can be interpreted as its index, so ABCDE yields 01234.
  • Both axis X and Y has the same number pattern, which is [0, 1, 2, 3, 4, 3, 2, 1]. That means, we just need to generate only one array to be used twice, for both axes.
  • Also if we inspect it deep enough, along the y axes, the alphabet indices matches the grid indices on each of the corresponding lines. on y=0, we got character index 0 which is A, on y=3 we got character index 3 which is D, and so on.
  • pivots, suprisingly, is always the number of characters used decreased by 1.

Then, all we have to do is:

  1. Decide what letters are going to be used. From letter A to the selected character, in ascending order. so we'd have ABCDE for letter E diamond.
  2. Decide the pivot. The maximum index of the letter has always the same value to the pivot.
  3. Generate an iterating array, it goes from 0, then to pivot, then descend back to 0. So, for example ,for letter E, we'll have [0, 1, 2, 3, 4, 3, 2, 1, 0] as iterating array.
  4. Loop over rows (y axis) as i using iterating array, then the columns (x axis) as j also using iterating array.
  5. In the loop, whenever the sum of i and j matches pivot, print the letter with index of i, instead just print a whitespace instead.

Code

pub fn get_diamond(c: char) -> Vec<String> {

Making the array of letters and the pivot

    //Prepare the set of valid alphabets, in order
    let complete = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
    //Find how long should the used letters array be
    let length = 
        complete //the complete alphabet string
            .chars() //convert into char iterator
            .enumerate() //enumerate each character from 0 in the beginning
            .map(|(i,x)|if x==c {1*i} else {0}) //mark which character is chosen as maximum used char, mapping them as i if true, else leave it be 0.
            .fold(0,|acc,x|acc+x)+1; //get the marked number as length
            
    //Determine the pivot. The pivot is always the length decreased by 1
    let pivot = &length - 1;
    
    //Determine the alphabets that we're only using
    let used =
        complete[..length] // The slice of relevant parts of complete alphabet
            .chars() // Convert it to character iterator
            .collect::<Vec<char>>(); // Recollect it as vector

Generating the iterating array

    let iterating =
        ((length as isize)-(((2 * &length ) - 1) as isize)..(length as isize)) //Make iterator from -length to length
            // The array yields [-4, -3, -2, -1, 0, 1, 2, 3, 4] for letter E now
            // as isize cast is obligatory because i use negative values. usize will cause overflow
        .map(|x|length-(x.abs() as usize)-1) //Remap the array by:
            // first absoluting all of them
            // then the result of subtracting variable length with each members of current array
            // is the new iterator, which yields [0, 1, 2, 3, 4, 3, 2, 1, 0] now.
            // Take note i convert it back to usize as it is positive now.
        .collect::<Vec<usize>>(); //Recollect it as vector

Looping over and printing

    let mut out: Vec<String> = Vec::new(); //Resulting string container
    
    //Looping
    for i in iterating.iter().cloned() {            //Iterate through the iterating vec
        let mut line = String::new();               //Prepare current line printing
        for j in iterating.iter().cloned() {        //Iterate through the iterating vec,again
            if &i+&j == pivot {line.push(used[i]);} //if sum of index i and j is same like pivot, then it's time to print char.
            else {line.push(' ');}                  //well if not, just a regular spacebar.
        }
        out.push(line); //At the end of the first level iteration, push the current line to container
    }

Returning

    out //Return the container as output
}

so that concludes that!