AdventJS 2023: Day 7 Challenge

AdventJS 2023: Day 7 Challenge

Drawing a 3D Gift!

·

4 min read

The solution to the Challenge #7 of AdventJS 2023

The solution to the previous challenge

The solution to the next challenge

Challenge Description

Santa is experimenting with new gift designs and he needs your help to visualize them in 3D.

Your task is to write a function that, given a size n (integer), generates a drawing of a 3D gift using ASCII characters.

The lines of the gifts are drawn with # and the faces with the symbol passed to us as a parameter:

drawGift(4, '+')

/*
   ####
  #++##
 #++#+#
####++#
#++#+#
#++##
####
*/

drawGift(5, '*')
/*
    #####
   #***##
  #***#*#
 #***#**#
#####***#
#***#**#
#***#*#
#***##
#####
*/

drawGift(1, '^')
/*
#
*/

Important: We have been told that there is always a new line at the end of the drawing.

Analysis

In this challenge, you have to draw gifts based on the parameters given by the exercise, in the pure style of ASCII Art. In case you haven't fully understood it, here's an example:

    #####
   #***##
  #***#*#
 #***#**#
#####***#
#***#**#
#***#*#
#***##
#####

The above is a 3D rectangle

Where # represents the outline of the rectangle, that is the lines, while the symbol they pass us as a parameter (in this case *) represents the face or surface of the rectangle.

Inputs

  1. Size (size): A number representing the size of the gift, it is the length in characters of each line of the gift.

  2. Symbol (symbol): A string that will fill the gift, basically fills each face of the rectangle.

Output

  • A string that will look like the drawing of the requested gift.

Considerations

  • Always leave a line break at the end of the drawing.

  • Take into account the spaces in the first half of the drawing, they are important to shape the gift.

Solution

The exercise itself is not very complex, the tricky part can be managing the string to draw, but JavaScript offers enough methods for it.

Code

function drawGift(size, symbol) {
  // The space at the beginning of the gift
  let space = size;

  // Initialize the first part of the gift
  // the space at the beginning of the gift
  // and concatenate # with the size of the gift
  let firstPart = " ".repeat(--space) + "#".repeat(size) + "\n";
  // if the size is 1 return the first part `#`
  if (size === 1) {
    return firstPart;
  }

  // Initialize the second part of the gift
  //this part is after the half of the gift
  let secondPart = "";
  // loop through the size of the gift
  for (let i = 1; i < size - 1; i += 1) {
    // start with the space at the beginning of the gift
    firstPart +=
      " ".repeat(--space) +
      // add `#` and the symbol with the size of the gift - 1
      "#".padEnd(size - 1, symbol) +
      // add `#` and fill the space with the symbol
      "#".padEnd(i + 1, symbol) +
      // add the break line
      "#\n";

    // The second part is the same but reversed
    secondPart +=
      "#" + symbol.repeat(size - 2) + "#".padEnd(size - i, symbol) + "#\n";
  }

  // half is `#` with the size of the gift and the symbol with the size of the gift - 2
  const half = "#".repeat(size) + symbol.repeat(size - 2) + "#\n";

  // return the first part, the half and the second part
  return firstPart + half + secondPart + "#".repeat(size) + "\n";
}

Community Solutions

Solution by marcode24:

const drawGift = (size, symbol) => {
  const WRAPPER = '#';
  const SPACE = ' ';

  if (size <= 1) return `${WRAPPER}\n`;

  const top = [SPACE.repeat(size - 1) + WRAPPER.repeat(size)];
  const bottom = [`${WRAPPER.repeat(size)}`];
  const middle = `${WRAPPER.repeat(size)}${symbol.repeat(Math.abs(size - 2))}`
    + `${WRAPPER}\n`;
  for (let i = 1; i < size; i++) {
    const line = `${WRAPPER}${symbol.repeat(size - 2)}${WRAPPER}`
      + `${symbol.repeat(i - 1)}${WRAPPER}`;
    top.push(SPACE.repeat(size - i - 1) + line);
    bottom.push(line);
  }

  top.pop();
  bottom.pop();
  top.push(middle);
  bottom.reverse();
  return `${top.join('\n')}${bottom.join('\n')}\n`;
};

Solution by Achalogy:

function drawGift(size, symbol) {
  let bgSize = size - 2

  bgSize += +!(bgSize + 1)

  let response = ""

  let topCenter = ""
  let bottomCenter = ""

  for (const a of [...Array.from({ length: bgSize }).keys()]) {
    const c = "#"
      + symbol.repeat(bgSize)
      + "#" + symbol.repeat(a) + "#"
    bottomCenter = c + "\n" + bottomCenter
    topCenter += " ".repeat(bgSize - a) + c + "\n"
  }

  response = " ".repeat(size - 1) + "#".repeat(size) + "\n"
    + (topCenter
      + "#".repeat(size) + symbol.repeat(bgSize) + "#" + "\n"
      + bottomCenter
      + "#".repeat(size) + "\n").repeat(+!!(size - 1))

  return response
}

And that was the challenge for December 7th and its solutions. Do you have another alternative solution? Leave it in the comments!