DEV Community

Daily Challenge #2 - String Diamond

dev.to staff on June 29, 2019

Welcome to Day 2 of our challenge series. Today, you’ll be using some clean and polished code to create a clean and polished diamond. Our challeng...
Collapse
 
alvaromontoro profile image
Alvaro Montoro • Edited

CSS

.diamond {
  --stars: 11;
  width: calc(var(--stars) * 10px);
  height: calc(var(--stars) * 15px);
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="10px" height="15px" viewBox="0 0 10 15"><text x="1.125" y="15" fill="black">*</text></svg>');
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}

Some people will claim that I am cheating with this one; and they are probably right... but it was fun to develop and it kind of works (although only with odd numbers 😭). The idea is:

  • Create a SVG image that shows an asterisk with text.
  • Put that SVG as an inline background image for an element.
  • Clip the element to only show a diamond shape (using clip-path).
  • Define a CSS variable to specify the number of stars in the middle of the diamond.
  • Knowing the size of the SVG image, use the CSS variable to calculate the height and width of the element.

Here there is a working demo on Codepen:

Collapse
 
coreyja profile image
Corey Alexander

Wow amazing one again! I don't think it's cheating at all, just a creative solution to the problem!

Collapse
 
alvaromontoro profile image
Alvaro Montoro

Thanks!
Yesterday's solution was definitely more cheating than this one.

Collapse
 
mrdulin profile image
official_dulin

Amazing! You are a CSS master!

Collapse
 
sajanv88 profile image
Sajan

Good job! :)

Collapse
 
coreyja profile image
Corey Alexander • Edited

After @andrewbrown shamed us all yesterday for not having test cases, I decided I needed to step up my game and went full TDD with this one!

Rust Solution:

fn concat_char(c: char, n: i32) -> String {
    (0..n).map(|_x| c).collect()
}

fn diamond_line(number_of_asteriks: i32, number_of_padding_spaces: i32) -> String {
    let spaces = concat_char(' ', number_of_padding_spaces);
    let asteriks = concat_char('*', number_of_asteriks);
    format!("{}{}{}\n", spaces, asteriks, spaces)
}

pub fn diamond(size: i32) -> Option<String> {
    if size <= 0 {
        None
    } else if size % 2 == 0 {
        None
    } else {
        let midpoint_index = (size - 1) / 2;

        let output: String = (0..size)
            .map(|line_number| {
                let number_of_padding_spaces = (line_number - midpoint_index).abs();
                let number_of_asteriks = size - number_of_padding_spaces * 2;

                diamond_line(number_of_asteriks, number_of_padding_spaces)
            })
            .collect();
        Some(output)
    }
}

#[cfg(test)]
mod tests {
    use crate::diamond;

    #[test]
    fn it_works_for_even_inputs() {
        assert_eq!(diamond(2), None);
        assert_eq!(diamond(4), None);
        assert_eq!(diamond(60), None);
    }

    #[test]
    fn it_works_for_negative_inputs() {
        assert_eq!(diamond(-2), None);
        assert_eq!(diamond(-5), None);
        assert_eq!(diamond(-11), None);
    }

    #[test]
    fn it_works_for_zero() {
        // This is not defined in the spec
        assert_eq!(diamond(0), None);
    }

    #[test]
    fn a_single_asterik_is_a_basic_diamond() {
        let expected_output = "*\n".to_string();
        assert_eq!(diamond(1), Some(expected_output));
    }

    #[test]
    fn it_works_with_a_small_diamond() {
        let expected_output = " * \n***\n * \n".to_string();
        assert_eq!(diamond(3), Some(expected_output));
    }

    #[test]
    fn it_works_with_a_large_diamond() {
        let expected_output = "     *     \n    ***    \n   *****   \n  *******  \n ********* \n***********\n ********* \n  *******  \n   *****   \n    ***    \n     *     \n".to_string();
        assert_eq!(diamond(11), Some(expected_output));
    }
}

Collapse
 
andrewbrown profile image
Andrew Brown 🇨🇦

+1 for Rust
+1 for TDD

Collapse
 
ben profile image
Ben Halpern

Nice!

Collapse
 
vbarinov profile image
Vlad Barinov

Hey! Also JavaScript

function diamond(n){
  if (n <= 0 || n % 2 === 0) {
    return null;
  }

  const repeater = ch => n => ch.repeat(n)
  const spacer = repeater(' ')
  const asterixer = repeater('*')

  let diam = ''
  for (let row = 1; row <= n; row++) {
    const spaces = Math.abs(n - ((2*row) - 1))
    const stars = n - spaces
    diam += `${spacer(spaces / 2)}${asterixer(stars)}\n`
  }

  return diam
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
monicat profile image
Monica Macomber

This is my favorite JS answer to this challenge 👍 I like how you used the repeater, keeps things clean & compact.

Collapse
 
auroratide profile image
Timothy Foster • Edited

Haskell!

import Data.Maybe

diamond :: Int -> Maybe [Char]
diamond n
  | n < 1     = Nothing
  | even n    = Nothing
  | otherwise = Just (concat $ map line rows)
  where
    line stars = replicate (div (n - stars) 2) ' ' ++ replicate stars '*' ++ "\n"
    rows = filter odd ([1..n] ++ reverse [1..(n - 2)])
Collapse
 
kunde21 profile image
Chad Kunde

Go (with bonus diamond of diamonds) playground link


func diamond(center int) (string, error) {
    if (center & 1) == 0 {
        return "", errors.New("center row must be an odd number")
    }
    return strings.Join(makeDiamond(center), "\n"), nil
}

func diamondOfDiamonds(center int) (string, error) {
    if (center & 1) == 0 {
        return "", errors.New("center row must be an odd number")
    }
    dmd := makeDiamond(center)
    outBuf := make([]string, center)
    row := strings.Repeat(" ", center)
    for i := 0; i <= center/2; i++ {
        rowBuf := make([]string, center)
        for j := range rowBuf {
            rowBuf[j] = strings.Repeat(row, center/2-i) + strings.Repeat(dmd[j], 2*i+1) + strings.Repeat(row, center/2-i)
        }
        outBuf[i], outBuf[center-i-1] = strings.Join(rowBuf, "\n"), strings.Join(rowBuf, "\n")
    }
    return strings.Join(outBuf, "\n"), nil
}

func makeDiamond(center int) []string {
    outBuf := make([]string, center)
    row := bytes.Repeat([]byte{' '}, center)
    for l, r := (center / 2), (center / 2); l >= 0; l, r = l-1, r+1 {
        row[l], row[r] = '*', '*'
        outBuf[center/2-l], outBuf[center/2+l] = string(row), string(row)
    }
    return outBuf
}
Collapse
 
coreyja profile image
Corey Alexander

Woah that's cool! I wanted to see what your diamond of diamonds looked like!

Thought I'd paste in the medium sized one, and let people go to the playground for the big one!

            *            
           ***           
          *****          
           ***           
            *            
       *    *    *       
      ***  ***  ***      
     ***************     
      ***  ***  ***      
       *    *    *       
  *    *    *    *    *  
 ***  ***  ***  ***  *** 
*************************
 ***  ***  ***  ***  *** 
  *    *    *    *    *  
       *    *    *       
      ***  ***  ***      
     ***************     
      ***  ***  ***      
       *    *    *       
            *            
           ***           
          *****          
           ***           
            *            

Collapse
 
erosilva profile image
Erô • Edited

JS ❤️

const diamontLayersStructure = (base) => {
    let diamontLayer = '';
    for (let baseIdx = 0; baseIdx < base; baseIdx++) {
        diamontLayer += '*';
    }
    return diamontLayer;
}

const diamont = base => {
    if (base % 2 === 0) {
        return null;
    }
    let diamontLayers = diamontLayersStructure(base);
    let diamontSpacement  = '';
    while (base !== 1) {
        base -= 2;
        diamontSpacement += ' ';
        let diamontNextLayer = diamontLayersStructure(base);
        diamontLayers = `${diamontSpacement}${diamontNextLayer}\n${diamontLayers}`;
        diamontLayers += `\n${diamontSpacement}${diamontNextLayer}`;
    }
    return console.log(diamontLayers);
}
diamont(10); //= null
diamont(11); //= diamont
Collapse
 
v613 profile image
Ceban Dumitru • Edited

BASH

drawAsteriks () {
  local n=${2};
  local row=${1};
  local numberOfSpaces=$(( (${n}-${row}-(${row}-1))/2 ));
  local numberOfchars=$(( ${n} - ${numberOfSpaces#-}*2 ));
  local spaces=$(printf '%*s' ${numberOfSpaces} '');
  local chars=$(printf '%*s' ${numberOfchars} '' | tr ' ' '+');
  local result=${spaces}${chars}${spaces};
  echo "${result}";
}

if [[ $((${1} % 2 )) = 0 ]]; then
  echo "the argument is even: ${1}";
else 
  for (( i = 1; i <= ${1}; i++ )); do
    drawAsteriks ${i} ${1};
  done;
fi
echo'';
Collapse
 
ben profile image
Ben Halpern • Edited

Ruby

def diamond(apex_size)
  shape_array = (1..apex_size).to_a + (1..apex_size -1).to_a.reverse
  shape_array.each { |num| puts diamond_row(apex_size, num) }
end

def diamond_row(apex_size, num)
  "#{" " * (apex_size - num)} #{"*" * ((num * 2 - 1))}"
end
Collapse
 
ben profile image
Ben Halpern

I didn’t follow the fine print so I’m not sure this totally fits the spec now that I’m reading more carefully.

I’ll be more careful tomorrow 😄

Collapse
 
highcenburg profile image
Vicente G. Reyes

Python

def diamond():

    num = 9

    for i in range(1, num+1):
      i = i - (num//2 +1)
      if i < 0:
        i = -i
      print(" " * i + "*" * (num - i*2) + " "*i)
diamond()
Collapse
 
garrett profile image
Garrett / G66

The shortest one by far

Collapse
 
highcenburg profile image
Vicente G. Reyes

It's also fast.

Collapse
 
kaspermeyer profile image
Kasper Meyer

Ruby solution

require "minitest/autorun"

class DiamondGenerator
  def initialize width
    @width = width
  end

  def generate
    return nil if invalid_width?

    number_of_asterisks.map { |n| number_to_asterisks(n) }.join("\n")
  end

  private

    def invalid_width?
      @width.even? or @width.negative?
    end

    def number_to_asterisks number
      ("*" * number).center(@width).rstrip
    end

    def number_of_asterisks
      steps = (1...@width).step(2).to_a
      steps + [@width] + steps.reverse
    end
end

class DiamondGeneratorTest < MiniTest::Test
  def test_valid_diamond
    expected_diamond = <<~DIAMOND.chomp
         *
        ***
       *****
      *******
     *********
    ***********
     *********
      *******
       *****
        ***
         *
    DIAMOND

    assert_equal expected_diamond, DiamondGenerator.new(11).generate
  end

  def test_diamond_with_even_width
    assert_nil DiamondGenerator.new(6).generate
  end

  def test_diamond_with_negative_width
    assert_nil DiamondGenerator.new(-2).generate
  end
end

Collapse
 
believer profile image
Rickard Natt och Dag

ReasonML / OCaml

Runnable example: sketch.sh/s/RvRBbbn6iqnEIumBYs7UwE/

type parity =
  | Even
  | Odd;

let testEven = value => value mod 2 == 0 ? Even : Odd;

let rec createDiamond = (~middleStars, ~shape=[], ~i=1, ()) => {
  switch (testEven(middleStars)) {
  | Even => None
  | Odd =>
    switch (middleStars - i) {
    | 0 =>
      Some(
        [List.rev(shape), [String.make(middleStars, '*')], shape]
        |> List.flatten
        |> String.concat("\n"),
      )
    | _ =>
      let padding = (middleStars - i) / 2;
      let row = Bytes.make(middleStars, ' ');

      Bytes.fill(row, padding, i, '*');
      let shape = [Bytes.to_string(row), ...shape];

      createDiamond(~middleStars, ~i=i + 2, ~shape, ());
    }
  };
};

switch (createDiamond(~middleStars=11, ())) {
| None => ()
| Some(d) => print_string(d)
};

Collapse
 
kesprit profile image
kesprit

My solution for Swift :

func diamond(size: Int, character: Character) {

    guard size > 2 else { return }

    var elements = [String]()
    var subsize = size

    while subsize > 2 {
        subsize -= 2
        elements.append(String(repeating: " ", count: (size - subsize) / 2) + String(repeating: character, count: subsize))
    }
    [elements.reversed(),[String(repeating: character, count: size)],elements].forEach { (tab) in
        tab.forEach { (string) in
            print(string)
        }
    }
}
Collapse
 
ganderzz profile image
Dylan Paulus • Edited

Dirty Nim, planning to rewriting. :)

import math

proc diamond(num: int): string =
  if num < 0:
    return ""

  let midPoint = floorDiv(num, 2)

  for row in 0..num:
    let distanceFromMid = abs(row - midPoint)
    let starsInRow = num - distanceFromMid * 2

    for col in 0..num:
      if col >= distanceFromMid + starsInRow or col <= distanceFromMid:
        result &= " "
      else:
        result &= "*"

    result &= "\n"

if isMainModule:
  const num = 30

  echo diamond(num)
Collapse
 
stevemoon profile image
Steve Moon • Edited

Erlang

-module(devto2).
-export([diamond/1]).

diamond(Max) when (Max > 2) and (Max rem 2 /= 0) ->
    print_stars(build_array(Max, 1, up, []));
diamond(_) ->
    error.


build_array(_, -1, down, Accum) ->
    Accum;
build_array(Max, Max, up, Accum) ->
    build_array(Max, Max - 2, down, Accum ++ [cur_line(Max, Max)]);
build_array(Max, Cur, up, Accum) ->
    build_array(Max, Cur + 2, up, Accum ++ [cur_line(Max, Cur)]);
build_array(Max, Cur, down, Accum) ->
    build_array(Max, Cur - 2, down, Accum ++ [cur_line(Max, Cur)]).


spaces(Max, Cur) ->
    lists:flatten(lists:duplicate(((Max - Cur) div 2), " ")).

stars(Cur) ->
    lists:flatten(lists:duplicate(Cur, "*")).

cur_line(Max, Cur) ->
    Spaces = spaces(Max, Cur),
    Stars = stars(Cur),
    lists:flatten([Spaces, Stars]).

print_stars([Cur | StarArray]) ->
    io:format("~s~n", [Cur]),
    print_stars(StarArray);
print_stars([]) -> 
    ok.
Collapse
 
coolshaurya profile image
Shaurya

Javascript

function diamond(input) {
    const blank = " "
    const full = "*"
    let output = ""

    if (input%2 === 0) {return null;}

    for (let i=1;i<input;i+=2) {
        spacing = blank.repeat((input-i)/2)
        output += spacing + full.repeat(i) + spacing + "\n"
        }

    output += full.repeat(input) + output.split("").reverse().join("")

    console.log(output)
    }

You can change the characters which are considered blank and full to create different effects.

normal output -

   *   
  ***  
 ***** 
*******
 ***** 
  ***  
   *   

with blank="*" and full="@" -

***@***
**@@@**
*@@@@@*
@@@@@@@
*@@@@@*
**@@@**
***@***
Collapse
 
coolshaurya profile image
Shaurya

If you mess with the fill/blank values, you get some nice art -

________shaurya________
_______shauryashauryashaurya_______
______shauryashauryashauryashauryashaurya______
_____shauryashauryashauryashauryashauryashauryashaurya_____
____shauryashauryashauryashauryashauryashauryashauryashauryashaurya____
___shauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashaurya___
__shauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashaurya__
_shauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashaurya_
shauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashauryashaurya
_ayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahs_
__ayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahs__
___ayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahs___
____ayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahsayruahs____
_____ayruahsayruahsayruahsayruahsayruahsayruahsayruahs_____
______ayruahsayruahsayruahsayruahsayruahs______
_______ayruahsayruahsayruahs_______
________ayruahs________
        11        
       111111       
      1111111111      
     11111111111111     
    111111111111111111    
   1111111111111111111111   
  11111111111111111111111111  
 111111111111111111111111111111 
1111111111111111111111111111111111
 111111111111111111111111111111 
  11111111111111111111111111  
   1111111111111111111111   
    111111111111111111    
     11111111111111     
      1111111111      
       111111       
        11        
        >>>>        
       >>>>>>>>>>>>       
      >>>>>>>>>>>>>>>>>>>>      
     >>>>>>>>>>>>>>>>>>>>>>>>>>>>     
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>    
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   
  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>    
     >>>>>>>>>>>>>>>>>>>>>>>>>>>>     
      >>>>>>>>>>>>>>>>>>>>      
       >>>>>>>>>>>>       
        >>>>        
        -->        
       -->-->-->       
      -->-->-->-->-->      
     -->-->-->-->-->-->-->     
    -->-->-->-->-->-->-->-->-->    
   -->-->-->-->-->-->-->-->-->-->-->   
  -->-->-->-->-->-->-->-->-->-->-->-->-->  
 -->-->-->-->-->-->-->-->-->-->-->-->-->-->--> 
-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->-->
 >-->-->-->-->-->-->-->-->-->-->-->-->-->-->-- 
  >-->-->-->-->-->-->-->-->-->-->-->-->--  
   >-->-->-->-->-->-->-->-->-->-->--   
    >-->-->-->-->-->-->-->-->--    
     >-->-->-->-->-->-->--     
      >-->-->-->-->--      
       >-->-->--       
        >--        
aaaaaaaaaaaaaaaa-aaaaaaaaaaaaaaaa
aaaaaaaaaaaaaa---aaaaaaaaaaaaaa
aaaaaaaaaaaa-----aaaaaaaaaaaa
aaaaaaaaaa-------aaaaaaaaaa
aaaaaaaa---------aaaaaaaa
aaaaaa-----------aaaaaa
aaaa-------------aaaa
aa---------------aa
-----------------
aa---------------aa
aaaa-------------aaaa
aaaaaa-----------aaaaaa
aaaaaaaa---------aaaaaaaa
aaaaaaaaaa-------aaaaaaaaaa
aaaaaaaaaaaa-----aaaaaaaaaaaa
aaaaaaaaaaaaaa---aaaaaaaaaaaaaa
aaaaaaaaaaaaaaaa-aaaaaaaaaaaaaaaa
*********************   *********************
******************     ******************
***************       ***************
************         ************
*********           *********
******             ******
***               ***

***               ***
******             ******
*********           *********
************         ************
***************       ***************
******************     ******************
*********************   *********************
************************ ************************
lallallallallallallallal lallallallallallallallal
lallallallallallallal   lallallallallallallal
lallallallallallal     lallallallallallal
lallallallallal       lallallallallal
lallallallal         lallallallal
lallallal           lallallal
lallal             lallal
lal               lal

lal               lal
lallal             lallal
lallallal           lallallal
lallallallal         lallallallal
lallallallallal       lallallallallal
lallallallallallal     lallallallallallal
lallallallallallallal   lallallallallallallal
lallallallallallallallal lallallallallallallallal
lalallalallalallalallalallalallalallalal lalallalallalallalallalallalallalallalal
lalallalallalallalallalallalallalal   lalallalallalallalallalallalallalal
lalallalallalallalallalallalal     lalallalallalallalallalallalal
lalallalallalallalallalal       lalallalallalallalallalal
lalallalallalallalal         lalallalallalallalal
lalallalallalal           lalallalallalal
lalallalal             lalallalal
lalal               lalal

lalal               lalal
lalallalal             lalallalal
lalallalallalal           lalallalallalal
lalallalallalallalal         lalallalallalallalal
lalallalallalallalallalal       lalallalallalallalallalal
lalallalallalallalallalallalal     lalallalallalallalallalallalal
lalallalallalallalallalallalallalal   lalallalallalallalallalallalallalal
lalallalallalallalallalallalallalallalal lalallalallalallalallalallalallalallalal
Collapse
 
coolshaurya profile image
Shaurya • Edited

Did this in rust too:

fn main() {
    let diamond_size = 17;

    println!("{}", gen_diamond(diamond_size));
}

fn gen_diamond(size: u8) -> String {
    if size % 2 == 0 || size < 3 {
        return "i i\nn n\nv p\na u\nl t\ni\nd".to_string();
    }

    let fill = "*";
    let blank = " ";

    let mut output = String::from("");

    let mut i = 1;
    while i <= (size - 2) {
        let blank_space = blank.repeat(usize::from((size - i) / 2));
        let filled_space = fill.repeat(usize::from(i));
        let line = format!("{0}{1}{2}\n", &blank_space, &filled_space, &blank_space);
        output.push_str(&line);
        i += 2
    }
    output = format!(
        "{0}{1}{2}",
        &output,
        fill.repeat(usize::from(size)),
        &output.chars().rev().collect::<String>()
    );

    output.to_string()
}

On invalid input, it returns -

i i
n n
v p
a u
l t
i
d
Collapse
 
celyes profile image
Ilyes Chouia • Edited

Too late but here it is anyway...

PHP:


function drawDiamond($diameter){
    if($diameter <= 2){
        trigger_error("provide more than 2 in diameter at least ! ", E_USER_WARNING);
    }else{
        $code = "<pre style='text-align: center; font-size: 22px;'>";
        for($i = 1; $i < $diameter; $i+=2){
            $code .= str_repeat("*", $i) . "<br>";
        }
        for($i = $diameter; $i >= 1; $i -= 2){
            $code .= str_repeat("*", $i) . "<br>";
        }
        $code .= "</pre>";
        return $code;
    }
}
echo drawDiamond(11);

Collapse
 
orenovadia profile image
orenovadia

I would like to add:
1) Making str.center do some of the dirty work
2) Using ranges (and chain) to iterate up and down instead of keeping a state on num


from itertools import chain

def diamond(n): 
    if n <=0 or n % 2 == 0:
        raise ValueError('n must be odd and positive') 
    for i in chain(range(1, n + 1, 2), reversed(range(1, n, 2))): 
        print(('*' * i).center(n)) 

diamond(1)
diamond(3)
diamond(5)

It might be more readable to have two loops instead of using chain but I like chaining more because I don't need to repeat the print

Thread Thread
 
highcenburg profile image
Vicente G. Reyes

Is this fast too?

Thread Thread
 
orenovadia profile image
orenovadia

I wouldn't worry about it too much, since print requires IO, it is by far the bottleneck.

For the rest of the utilities that I used: range, chain, and str.center: they are all implemented in C if you are using the standard CPython (should be fast).

To avoid the IO, let's compare the two functions as generators of strings (I replaced the print with yield (('*' * i).center(n)) for both my implementation and Nicks:

In [39]: %timeit tuple(my_diamond(11))                                                                                                                                                                                 
3.59 µs ± 37.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [40]: %timeit tuple(nicks_diamond(11))                                                                                                                                                                           
4.66 µs ± 69.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Seems like mine is slower than Nicks.
However, on my machine, a single print statement takes about 4.17us, which is almost as long as diamond(11) takes without any prints!

Collapse
 
sapien profile image
Prateek Thapa • Edited

Just submitted my kata. <3 codewars.
Start from the middle, and go on appending stars to the top and bottom respectively.

Python:

def is_negative(n):
  return n <= 0

def is_even(n):
  return n % 2 == 0

def stars_with_spaces(num_stars, num_spaces):
  return num_spaces * ' ' + num_stars * '*' + '\n'

def diamond(n):
  if (is_negative(n) or is_even(n)):
    return None

  res = [None] * n
  mid_point = int((n - 1) / 2)

  num_stars = n
  num_spaces = 0

  for i in range(mid_point + 1)[::-1]:
    stars = stars_with_spaces(num_stars, num_spaces)

    res[mid_point - num_spaces] = stars
    res[mid_point + num_spaces] = stars

    num_spaces += 1 
    num_stars -= 2

  return ('').join(res)
Collapse
 
karstencoba profile image
karsten-coba

Gave it a try in Python. Not exactly as required since the diamond is printed on-the-fly, but I think it shows the main idea to create every line one after the other. Could also be stored in a string and then returned...

import sys

def diamond(width):
    padding = width//2

    while padding > -width//2:
        print(" " * abs(padding) + "*" * (width - abs(padding) * 2))
        padding -= 1

if (len(sys.argv) < 2 or int(sys.argv[1]) < 1 or int(sys.argv[1]) % 2 == 0):
    print("Invalid parameter")
else:
    diamond(int(sys.argv[1]))
Collapse
 
gnsp profile image
Ganesh Prasad
const diamond = num => console.log(
    (isNaN(num) || num < 0 || num % 2 === 0) ? null
    : Object.keys(Array(Number(num)).fill(1))
        .map(i => [
            Math.abs(Number(num) - (2*i + 1))/2,
            Number(num) - Math.abs(Number(num) - (2*i + 1))
        ])
        .map(([spaces, asterisks]) => [
            ...Array(spaces).fill(' '),
            ...Array(asterisks).fill('*'),
            ...Array(spaces).fill(' '),
        ])
        .map(line => line.join(''))
        .join('\n')
);
Collapse
 
martyhimmel profile image
Martin Himmel

PHP

function make_diamond(int $width) {
    if ($width < 0 || $width % 2 == 0) {
        return null;
    }
    for ($i = 1; $i < $width; $i += 2) {
        echo str_repeat(' ', $width - $i / 2) . str_repeat('*', $i) . PHP_EOL;
    }
    for ($j = $width; $j > 0; $j -= 2) {
        echo str_repeat(' ', $width - $j / 2) . str_repeat('*', $j) . PHP_EOL;
    }
}
Collapse
 
viniciuscavagnolli profile image
Vinicius Cavagnolli • Edited

Playing with StringBuilder on C#

string Diamond(int i)
{
    if (i < 0 || i % 2 == 0) return null;
    var sb = new StringBuilder().Append(Environment.NewLine).Append('*', i).Append(Environment.NewLine);
    for (int x = i; i >= 1; --x)
    {
        sb.Append(' ', x - i).Append('*', i).Append(Environment.NewLine).Insert(0, "*", i).Insert(0, " ", x - i).Insert(0, Environment.NewLine);
        i -= 2;
    }
    return sb.ToString();
}

And Visual Basic.NET

Private Function Diamond(ByVal i As Integer) As String
    If i < 0 OrElse i Mod 2 = 0 Then Return Nothing
    Dim sb = New StringBuilder().Append(Environment.NewLine).Append("*"c, i).Append(Environment.NewLine)
    Dim x = i
    i -= 2

    While i >= 1
        x -= 1
        sb.Append(" "c, x - i).Append("*"c, i).Append(Environment.NewLine).Insert(0, "*", i).Insert(0, " ", x - i).Insert(0, Environment.NewLine)
        i -= 2
    End While

    Return sb.ToString()
End Function
Collapse
 
centanomics profile image
Cent

Just used some for loops to print all of the asterisks, after doing a check for over 0 and odd, and added some css to make the shape of a diamond.

Codepen


const stringDiamond = rows => {
  if (rows > 0 && rows % 2 === 1) {
    let diamond = "";
    for(let i = 1; i< rows + 1; i += 2) {
      diamond += "<p>";
      for(let j = 1; j < i + 1; j++) {
        diamond += "*";
      }
      diamond += "</p>";
    }
    for(let i = rows - 2; i> 0; i-=2) {
      diamond += "<p>";
      for(let j = 1; j < i + 1; j++) {
        diamond += "*";
      }
      diamond += "</p>";
    }
    return diamond;
  } else {
    return "null"
  }
}

The CSS making the asterisks look like a diamond


#answer {
  text-align: center;
  line-height: 5px;
}

Collapse
 
andreasjakof profile image
Andreas Jakof

A bit late, but with functional flavoured C#

public static string Diamond(ulong n)
{
    if ((n % 2) == 0)
       return null;

    ulong maxIndent = (n-1) / 2;
    StringBuilder sb = new StringBuilder();
    sb.WriteRows(maxIndent, maxIndent, end => end > 0, i => i-1);
    sb.WriteRows(maxIndent, 0, end => end <= maxIndent ,i => i+1);
    return sb.ToString();
}

public static void WriteRows(this StringBuilder sb, ulong maxIndent, ulong start, Func<ulong,bool> condition, Func<ulong,ulong> step)
{
    for (ulong indent = start; condition(indent); indent = step(indent) )
    {
        sb.WriteChars(indent,' ');
        sb.WriteChars(maxIndent - indent,'*');
        sb.Append("*");
        sb.WriteChars(maxIndent - indent,'*');
        sb.WriteChars(indent,' ');
        sb.WriteLine(); //make a NewLine
    }

}

private static void WriteChars(this StringBuilder sb, ulong count, char c)
{
    for (ulong i = 0; i< count; ++i)
    {
        sb.Append(c);
    }
}

Collapse
 
propthink profile image
propthink

No one will see this but I spent a couple of hours trying to figure it out:

#include <iostream>

// value dictates total number of asterisks in middle row
bool print( int value )
{
    // if user value is even, or equal to zero
    if( ( value % 2 ) == 0 || value == 0 )
    {
        return false;
    }
    // iterate through each possible ascending row
    for( int i { 0 }; i <= value; ++i )
    {
        // only print new row on odd-numbered values
        if( ( i % 2 ) != 0 )
        {
            // print buffer for alignment
            for( int j { 0 }; j < ( ( value - i ) / 2 ); ++j )
            {
                std::cout << " ";
            }
            // print this row
            for( int k { 0 }; k < i; ++k )
            {
                std::cout << "*";
            }
            std::cout << '\n';
        }
    }
    // iterate through each possible descending row
    // avoid printing the middle row twice
    for( int i { value - 1 }; i > 0; --i )
    {
        // only print new row on odd-numbered values
        if( ( i % 2 ) != 0 )
        {
            // print buffer for alignment
            for( int j { 0 }; j < ( ( value - i ) / 2 ); ++j )
            {
                std::cout << " ";
            }
            // print this row
            for( int k { 0 }; k < i; ++k )
            {
                std::cout << "*";
            }
            std::cout << '\n';
        }
    }
    return true;
}

int main()
{
    if( !print( 11 ) )
    {
        std::cout << "invalid input detected!" << '\n';
    }
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
peter279k profile image
peter279k

Here is my simple diamond solution with Python:

def diamond(n):
    # Make some diamonds!
    if n % 2 == 0 or n <= 0:
        return None
    if n == 1:
        return "*\n"

    array = list(range(1, n+1))
    result = ""
    white_space_count = list(range(1, int((n - (n % 2)) / 2)+1))
    white_space_count.reverse()
    white_space_index = 0
    for count in array:
        if count % 2 == 0:
            continue
        if white_space_index != len(white_space_count):
            result += (" " * white_space_count[white_space_index])
            white_space_index += 1
        result += ("*" * count) + "\n"

    array.reverse()
    array = array[1:]
    white_space_count.reverse()
    white_space_index = 0

    for count in array:
        if count % 2 == 0:
            continue
        if white_space_index != len(white_space_count):
            result += (" " * white_space_count[white_space_index])
            white_space_index += 1
        result += ("*" * count) + "\n"

    return result
Collapse
 
dimitrilahaye profile image
Dimitri Lahaye

Sorry for that (JS)

function diamond(int) {
  if (int < 0 || !(int % 2)) {
    return null;
  }
  write = (i,j) => ' '.repeat(j) + '*'.repeat(i) + '\n';
  let ret = '';
  for (let i = 1, j = Math.floor(int / 2); j >= 0; j--, i += 2) {
    ret += write(i,j);
  }
  for (let i = int - 2, j = 1; j < int && i > 0; j++, i -= 2) {
    ret += write(i,j);
  }
  return ret;
}
Collapse
 
jasman7799 profile image
Jarod Smith
print((lambda maxStars = int(input("Star Count: ")) : "Can't be a star =(" if not maxStars % 2 else "".join(map(lambda i: "".join([" "]*(int((maxStars - ((i+1) * 2 - 1 if (i+1) * 2 - 1 <= maxStars else (maxStars-(i+1) + 1)*2 -1))/2)) + ["*"]*((i+1) * 2 - 1 if (i+1) * 2 - 1 <= maxStars else (maxStars-(i+1) + 1)*2 -1)) +"\n", range(maxStars))))())

one line functional python, why I dunno.

Collapse
 
jasman7799 profile image
Jarod Smith • Edited
// Will print a diamond with n stars in the middle line
function printDiamond(n) {

  // validate input
  if (n % 2 === 0)
    throw new Error("can't have middle row size of an even number");
  if (n < 0)
    throw new Error('input must be a positive number');

  const numLines = n;
  let spaces = n - 1; 
  let stars = 1;
  const middleLine = Math.floor(numLines/2);

  for(let i = 0; i < numLines; i++) {
    console.log(buildLine(stars, spaces));
    // before the middle line we will increment the number of stars by 2
    if(i < middleLine) {
      stars += 2;
      spaces -= 2;
    }
    // after the middle line we decrement the number of stars by 2
    else {
      stars -= 2;
      spaces += 2;
    }
  }
}

// will build a line with the correct number of stars and spaces
// ie given 3 stars and 2 spaces
// will build ' *** '
function buildLine(stars, spaces) {
  let line = '';
  const lineSize = stars+spaces;

  // the first index in the line with a star.
  const starIndex = Math.floor((lineSize-stars)/2);

  for(let i = 0; i < lineSize; i++) {
    // starts building stars
    if(i >= starIndex && stars > 0) {
      line += '*';
      stars--;
    }
    else
      line += ' ';
  }

  return line;
}

deviated from the spec in one specific way where I don't return null if a an even number or negative number is provided but instead throw an error.
I feel however this gives more information to the user.

Collapse
 
bauripalash profile image
Palash Bauri 👻

Another 🚀

Python

def challenge2(n):
    pad = n//2
    D = ""
    while pad > -n//2:
        D = " " * abs(pad) + "*" * (n - abs(pad) *2) + "\n" + D
        pad -= 1
    return D
Collapse
 
cloudyhug profile image
cloudyhug

Haskell

import Data.List

diamond :: Int -> Maybe String
diamond n
  | even n || n < 0 = Nothing
  | otherwise       = Just diamondLines
  where
    makeLine k = replicate (div (n - k) 2) ' ' ++ replicate k '*'
    diamondLines = unlines $ map makeLine ([1, 3 .. n] ++ [n - 2, n - 4 .. 1])
Collapse
 
choroba profile image
E. Choroba

Let's go functional in Perl! (Tests included).

#!/usr/bin/perl
use warnings;
use strict;

use Test::More;

sub diamond {
    my ($n) = @_;
    return if $n < 1 or 0 == $n % 2;

    return join "\n",
           map { ' ' x (($n - $_) / 2) . '*' x $_ }
           grep $_ % 2,
           1 .. $n, reverse 1 .. $n - 1
}

is diamond(0), undef;
is diamond(1), "*";
is diamond(2), undef;
is diamond(3), " *\n***\n *";
is diamond(5), "  *\n ***\n*****\n ***\n  *";

done_testing();
Collapse
 
ojune18 profile image
ojune18

JS

function print_stars(num) {
    if (num % 2 == 0) {
        return null;
    }
    let i = 1;
    let space = parseInt(num / 2);
    while (i < num) {
        console.log(`${" ".repeat(space)}${"*".repeat(i)}${" ".repeat(space)}`);
        i += 2
        space -= 1
    }
    while (i > 0) {
        console.log(`${" ".repeat(space)}${"*".repeat(i)}${" ".repeat(space)}`);
        i -= 2;
        space += 1;
    }
}

try {
    print_stars(parseInt(process.argv[2]))
}
catch (err) {
    console.error(err);
}
Collapse
 
sampathbalivada profile image
Sai Sampath Kumar

Here's something with C++ (My personal favourite)

#include<iostream>
using namespace std;

int main() {
  int num;
  cin >> num;

  if(num%2 == 0 || num < 0) {
    return 0;
  }

  int spaces = num/2;

  for(int i=1; i<=num; i+=2, spaces--) {
   for(int j=0; j<spaces; j++){
     cout << " ";
   }
   for(int j=0; j<i; ++j) {
     cout << "*";
   }
   cout << endl;
  }

  for(int i=num; i>0; i-=2, spaces++) {
   for(int j=0; j<spaces; j++){
     cout << " ";
   }
   for(int j=0; j<i; ++j) {
     cout << "*";
   }
   cout << endl;
  }
  return 0;
}
Collapse
 
johncip profile image
jmc • Edited

Clojure:

(defn row [max i]
  (apply str (concat (repeat (- max i) \space)
                     (repeat (inc (* 2 i)) \*))))

(defn diamond [max]
  (let [is (range 0 max)]
    (->> (concat is (rest (reverse is)))
         (map (partial row max))
         (clojure.string/join \newline))))

as pseudocode:

row = fn(max, i) =>
    pad = " " * (max - i)
    stars = "*" * (2 * i + 1)
    stars + pad

diamond = fn(max) =>
    top_nums = up_to(0, max)
    btm_nums = drop_first(reverse(top_nums))
    rows = row(max, i) for each i in (top_nums + btm_nums) 
    join(rows, "\n")
Collapse
 
protium profile image
protium

Here my solution: form the upper side and reuse it.
Assuming string concatenation has linear execution time, this solution should be O(middle*num). Please correct me if I'm wrong

function diamond(num) {
  if (num % 2 <= 0) return null;

  let result = "";
  const middle = Math.floor(num / 2) + 1;
  let lines = []
  for (let i = 0; i < middle; i++) {    
    lines[i] = "";
    for (let j = 0; j < num; j++ ) {
        lines[i] += j >= middle - 1 - i && j <= middle - 1 + i ? "*" : " ";      
    }
    result += lines[i] + "\n";
  }

  // reuse the triangle
  for (let i = lines.length - 2; i >= 0; i-- ) {
    result += lines[i] + "\n";
  }

  return result;
}
Collapse
 
mdarrik profile image
Darrik Moberg • Edited

This took me longer than it should have. But I haven't worked with R in almost 2 years. Sure you could do it more efficiently with just a loop, but I learned some stuff about concatenating matrices to strings in R this way so I call it a win.

R:

diamond <- function(n) {
  if(!n %% 2 || n<=0) { return(NA)}
  else if(n==1) { return("*")}
  matrix(1:n, nrow=(n*2 - 1), ncol=n, byrow = TRUE)
  numStarsPerRow <- matrix(c(seq(from = 1, to= n, by=2),
                             seq(from=n-2, to = 1, by = -2)),
                           nrow=n, ncol=n)
  startcol <- matrix(c(seq(from =(n+1)/2, to = 1, by = -1),
                       seq(from = 2, to = (n+1)/2, by = 1)),
                     nrow=n,ncol=n)
  colNum <- matrix(1:n, ncol=n, nrow=n,
                   byrow = TRUE)
starBools <- (colNum >= startcol & colNum <= (startcol + numStarsPerRow) -1)
paste(apply(ifelse(starBools,"*"," "),2,paste, collapse=""),collapse ="\n")
}
Collapse
 
thepeoplesbourgeois profile image
Josh • Edited

ruby diamonds? Okay!

def riamond(karat)
  unless karat.odd? && karat > 0
    raise ArgumentError.new("You want a #{karat} karat diamond? That's crazy!")
  end
  cut = 1
  layers = []
  until cut > karat
    layers.push(("*" * cut).center(karat))
    cut += 2
  end
  cut = karat
  until cut <= 1
    cut -= 2
    layers.push(("*" * cut).center(karat))
  end
  puts layers.join("\n")
end

alias diamond riamond # since we're gonna use "actual words" i guess

> diamond(9)
    *    
   ***   
  *****  
 ******* 
*********
 ******* 
  *****  
   ***   
    *    

> riamond(3)
 * 
***
 * 

> riamond(5)
  *  
 *** 
*****
 *** 
  *  
> riamond(-5)
# => ArgumentError (You want a -5 karat diamond? That's crazy!)

> riamond(8)
# => ArgumentError (You want a 8 karat diamond? That's crazy!)
Collapse
 
bernstein7z profile image
Alan Bernstein

JS

const diamond = (astericks = 0) => {
    try {
        if (astericks % 2 === 0 || astericks < 0) {return null;} 
        else {
            if (astericks === 1) {console.log("*")}
            else {
                let array = [];
                for (let i = 1, j = 0; i<=astericks; i += 2, j++) {
                    let count = Math.floor(astericks / 2) - 1 - j;
                    if (count >= 0) {
                        array.push(" ".repeat(count) + "*".repeat(i));
                    }
                }

                let temp = [...array];
                array.pop();
                let arrayHelper = [...temp, ...array.reverse()];

                for (let i = 0; i <arrayHelper.length; i++) {
                    console.log(arrayHelper[i]);
                }
            }
        }
    } catch (e) {
        console.log(e);
    }
}
Collapse
 
0xyasser profile image
Yasser A

Python

def asterisk():
    n = [*range(1,10), *reversed(range(1,9))]
    for r in n:
        l = []
        for c in n:
            x = r + c - 9
            l.append('*' if x > 0 else ' ')
        print(' '.join(l))
Collapse
 
praneetnadkar profile image
Praneet Nadkar

C# Just two main loops to print upper and lower part. One loop to calculate no of rows

var diagonalLength = int.Parse(Console.ReadLine());
if (diagonalLength %2 == 0 || diagonalLength < 0)
{
   Console.WriteLine("null");
   Console.ReadKey();
   return;
}

var rowCount = 0;

// calculate the no of rows needed
for (int i = 1; i < diagonalLength; i += 2)
{
   rowCount += 1;
}
var number = diagonalLength;
var j = rowCount;
// upper part of the diamond
for (int i = 1; i <= number; i += 2, j--)
{
   Console.Write(new string(' ', j));
   Console.Write(new string('*', i));
   Console.WriteLine(new string(' ', j));
}

j = 1;
number = diagonalLength - 2;
// lower diamond
for (int i = number; i >= 1; i -= 2, j++)
{
  Console.Write(new string(' ', j));
  Console.Write(new string('*', i));
  Console.WriteLine(new string(' ', j));
}
Collapse
 
wolverineks profile image
Kevin Sullivan
const reverse = xs => xs.reduce((result, current) => [current, ...result], []);

const padding = width => " ".repeat(width);
const emptyRows = width => Array(width).fill(null);
const stars = count =>
  Array(count)
    .fill(null)
    .map(() => "*")
    .join(" ");
const topRows = width => reverse(bottomRows(width));
const centerRow = width => stars(width);
const bottomRows = width =>
  emptyRows(width - 1).map(
    (_, index) => `${padding(index + 1)}${stars(width - (index + 1))}`,
  );

export const stringDiamond = width => {
  if (width % 2 === 0) return null;
  if (width <= 0) return null;
  return [...topRows(width), centerRow(width), ...bottomRows(width)].join(`\n`);
};

Collapse
 
rafi993 profile image
Rafi

Rust

fn print_star(n: usize, i:usize) {
    println!("{}{}", " ".repeat(n - i), "*".repeat(i * 2 + 1))
}

fn main() {
    let n = 5;
    for i in 0..n {
        print_star(n, i);
    }

    for i in (0..n).rev() {
        print_star(n, i);
    }
}
Collapse
 
rafi993 profile image
Rafi • Edited

SQL (Postgres)


\set x 5

select concat(repeat(' ', :x - n), repeat('*',2 * n + 1))
   from (select * from generate_series(0, :x) as n
     union all
         select * from generate_series(:x - 1, 0, -1) as n) as n;

Collapse
 
vinniew1rus profile image
Vinnie

Extremely late to the party but here's my solution in JS:


const diamond = (size) => {
    if (size % 2 == 0 || size < 1) return null;

    const top = [...Array(size+1).keys()].reduce((acc, item) => {
        if(item % 2 != 0) acc.push([...Array((size - item) / 2).fill(' '), ...Array(item).fill('*'), ...Array((size - item) / 2).fill(' ')]);
        return acc;
    },[]);

    return [...top, ...top.splice(0, top.length -1).reverse()].map(row => row.join('')).join('\r\n');
}
Collapse
 
mellamoadan profile image
Adan ϟ

Dart

import 'dart:io';

main(){
  stdout.writeln('Center Lenght?');
  int center = int.tryParse(stdin.readLineSync());
  if(center == null || center%2 == 0){
    print('Center can\'t be null or an even number');
  }

  for(var i = 1; i < center; i+=2){
    print((" " * ((center - i) ~/ 2 )) + ("*" * i));
  }
  for(var i = center; i >= 1; i-=2){
    print((" " * ((center - i) ~/ 2 )) + ("*" * i));
  }
}
Collapse
 
tblanshard profile image
Tallie

My solution using Python :)

def diamond(mid):
    if (mid % 2 == 0) or (mid < 0):
        return None
    else:
        spaces = (mid - 1) // 2
        asterisks = 1
        while asterisks < (mid):
            print((" " * spaces) + ("*" * asterisks) + (" " * spaces))
            spaces -= 1
            asterisks += 2
        spaces = 0
        asterisks = mid
        while asterisks > 0:
            print((" " * spaces) + ("*" * asterisks) + (" " * spaces))
            spaces += 1
            asterisks -= 2
Collapse
 
cvanpoelje profile image
cvanpoelje

JavaScript

diamond = width => {
  diamond = '';
  index = width * -1;
  while (index < width + 1) {
    counter = index;
    if (index < 0) {
      counter = index * -1;
    }
    diamond = diamond.concat(" ".repeat(counter + 1) + " *".repeat(width - counter)+'\n');
    index++;
  }
  return diamond;
};
console.log(diamond(6));
Collapse
 
neotamizhan profile image
Siddharth Venkatesan

Ruby

def diamond(middle)
  return nil if middle < 0 or middle.even?
  d = []
  (1..middle).step(2).each do |i|
    spaces = " " * ((middle - i).to_i/2)    
    d << "#{spaces}#{"*" * i}#{spaces}"
  end  
  d + d[0..-2].reverse  
end

puts diamond(7)
Collapse
 
figueroadavid profile image
David Figueroa

Powershell

It will automatically center to the specified line width, and requires that the line be at least as wide as the diamond itself.

function show-diamond {
    param(
        [ValidateScript( {$_ -ge 11} )]
        [int]$LineWidth = 11
    )

    $range = [System.Collections.Generic.List[int]]::new()
    (1..11).Where{$_ % 2 -gt 0} | ForEach-Object { $range.Add($_) }
    (9..1).Where{$_ % 2 -gt 0} | ForEach-Object { $range.Add($_) }

    $output = [System.Collections.Generic.List[string]]::new()
    for ($i = 0; $i -lt $range.Count; $i++) {
        $MidPoint = [math]::Round(($LineWidth - $range[$i]) / 2, [System.MidpointRounding]::AwayFromZero)
        $String = '{0}{1}' -f (' ' * $MidPoint), ('*' * $range[$i])
        $output.Add($string)
    }
    $output
}

David F.

Collapse
 
lucasromerodb profile image
Luke • Edited

JS

const drawRow = (qty, replaceWith) => {
  let str = "";
  for (let i = 0; i < qty; i++) {
    str += replaceWith;
  }

  return str;
};

const printDiamond = (n) => {
  if (n % 2 === 0 || n < 0) {
    return "The number should be odd and positive";
  }

  let row = "";
  let stars = 0;

  for (let i = 0; i < n; i++) {
    if (i > parseInt(n / 2)) {
      stars -= 2;
    } else {
      stars = i * 2 + 1;
    }

    const spaces = (n - stars) / 2;

    row += drawRow(spaces, " ");
    row += drawRow(stars, "*");
    row += drawRow(spaces, " ");

    if (i !== n - 1) {
      row += "\n";
    }
  }

  return row;
};

console.log(printDiamond(11));
Collapse
 
caleb_rudder profile image
Caleb Rudder

C++

if (middleRow % 2 != 0 && middleRow > 0) {

    for (int i = 0; i <= middleRow/2; i++) {
        int space = (middleRow / 2) -i;

        for (int k = 0; k < space; k++) {
            cout << " ";
        }

        for (int j = 0; j <= (i*2); j++) {
            cout << "*";
        }

        cout << endl;
    }

    int space = 1;
    for (int i = middleRow; i >= (middleRow / 2); i--) {


        for (int k = 0; k < space; k++) {
            cout << " ";
        }

        for(int j = 0; j < middleRow-(space*2); j++) {
            cout << "*";
        }
        space++;
        cout << endl;
    }
}
else {
    cout << "Number must be non negative and odd." << endl;
}
Collapse
 
khaloscar profile image
khaloscar

Implemented this in rust with some tests. I am still learning and got a lot of experimentation done. Idk how much it matters in this case but I tried pre-allocating capacities for any vectors or strings.

At first I used modulo to get uneven numbers in the for loop but I got stuck doing it.
Fond a solutuion here in the comments of a guy using abs-values, that inspired me to instead only create the diamond up to its mid-row and then reflect it around that row.

Could maybe improve and use iterators instead of for-loop, idk?
with.capacity(), seems to take usize only, some improvement could be done here, for example I convert to usize for each capacity call.
Adding the padding at the end of a line isnt really neccessary?

fn diamond(length: i32) -> Option<String> {

    // Return early with None if len less than 1
    if length < 1 {
        return  None;
    }

    // Find mid-row/mid-point 
    // and pre-alloc capacity for output-vector
    // note capacity seems to determine amnt of elements
    // not capacity to hold data(?)
    let midpoint = (length + 1)/2;
    let mut output = Vec::with_capacity(length as usize);

    // Create each line up to and including midrow, padding decreases
    // => asterixes increases
    for i in 1..=midpoint {
        let mut line = String::with_capacity(length as usize);
        let pad = midpoint - i;
        let padding = concat_char_cap(' ', pad);
        let asterix = concat_char_cap('*', length-pad*2);

        // push the strings together to form the line
        line.push_str(&padding);
        line.push_str(&asterix);
        line.push_str(&padding);
        line.push_str("\n");

        // push into output_vector
        output.push(line);
    }
    //reflect half of the vector around its center row
    // maybe this could save some computation for
    // larger diamonds
    let mut beg = output[0..output.len()-1].to_vec();
    beg.reverse();
    output.append(&mut beg);

    // create iterator and collect into String.
    // wrap around Some
    Some(output.into_iter().collect())

}

fn concat_char_cap(c: char, n: i32) -> String {
    // pre-alloc string with capacity, 
    // maybe its more efficient for larger rows
    let n = n as usize;
    let mut output = String::with_capacity(n);

    if n == 1 {
        output.push(c);
    } else if n > 1 {
        for _i in 0..=n-1 {
            output.push(c);
        }      
    }

    output
}

fn main() {

    println!("{:?}", diamond(0));

}



#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn case_successful_dimaond() {
        let midrow = 5;
        let expected = "  \
  *  
 *** 
*****
 *** 
  *  \n".to_string();

    assert_eq!(diamond(midrow), Some(expected));
    }

    #[test]
    fn case_empty_diamond() {
        let midrow = 0;

        assert_eq!(diamond(midrow), None);
    }

    #[test]
    fn case_negative_diamond() {
        assert_eq!(diamond(-2), None)
    }
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
patricktingen profile image
Patrick Tingen

Progress 4GL solution:

Code in the ABL Dojo here

Collapse
 
alepop profile image
Aleksey
const diamond = value => {
  if (value < 1 || value % 2 === 0) return null;
  const side = [];
  const center = '*'.repeat(value);
  for (let i = value - 2; i > 0; i -= 2) {
    let rest = (value - i) / 2;
    side.push(' '.repeat(rest) + '*'.repeat(i) + ' '.repeat(rest))
  }
  return [ ...[...side].reverse(), center, ...side].join('\n');
}
Collapse
 
hectorpascual profile image
Héctor Pascual

Python :

def diamond(mid_len):
    if not mid_len or mid_len % 2 == 0 or mid_len <= 2:
        return None
    for i in range(1, 2*mid_len):
        if i % 2 != 0:
            if i < mid_len:
                print(' '*(int(mid_len/2)-int(i/2)) + '*'*i)
            else:
                print(' '*(int(i/2)-int(mid_len/2)) + '*'*(2*mid_len-i))
Collapse
 
mwlang profile image
Michael Lang

Ruby Language Version

def diamond carats
  return unless carats > 0 && carats.odd?
  top = 1.step(carats, 2).map{|i| (" " * ((carats - i) / 2)) << ("*" * i)}
  bottom = top.reverse[1..-1]
  (top + bottom).join("\n")
rescue
  nil
end

10.times{|i| puts diamond(i) }

require "spec"

describe "#diamond" do
  it { expect(diamond -1).to be_nil }
  it { expect(diamond 0).to be_nil }
  it { expect(diamond 3.0).to be_nil }
  it { expect(diamond 4).to be_nil }
  it { expect(diamond "foo").to be_nil }
  it { expect(diamond 1).to eq "*" }
  it { expect(diamond 3).to eq " *\n***\n *" }
  it { expect(diamond 5).to eq "  *\n ***\n*****\n ***\n  *" }
  it { expect(diamond 7).to eq "   *\n  ***\n *****\n*******\n *****\n  ***\n   *" }
  it { expect(diamond 9).to eq "    *\n   ***\n  *****\n *******\n*********\n *******\n  *****\n   ***\n    *" }
  it { expect(diamond 11).to eq "     *\n    ***\n   *****\n  *******\n *********\n***********\n *********\n  *******\n   *****\n    ***\n     *" }
end

output

>> rspec diamond.rb

*

 *
***
 *

  *
 ***
*****
 ***
  *

   *
  ***
 *****
*******
 *****
  ***
   *

    *
   ***
  *****
 *******
*********
 *******
  *****
   ***
    *
...........

Finished in 0.00719 seconds (files took 0.15133 seconds to load)
11 examples, 0 failures
Collapse
 
margo1993 profile image
margo1993

My go exercise two

func BuildAsteriskDiamond(weight int) (string, error) {
    if weight < 3 {
        return "", errors.New("Can't build diamond less than 3 asterisk")
    }

    if weight % 2 == 0 {
        return "", errors.New("Even number is not allowed!")
    }

    result := ""
    var height int = weight / 2
    var lineWidth int = height + 1
    asteriskCount := 1

    for i := 0; i < weight; i++ {
        spacesCount := abs(height - i)

        result = result + repeatCharacter(" ", spacesCount) + repeatCharacter("*", asteriskCount) + "\n"

        if i < height {
            asteriskCount += 2
            lineWidth++
        } else {
            asteriskCount -= 2
            lineWidth--
        }
    }

    return result, nil
}

func repeatCharacter(character string, count int) string {
    result := ""
    for i := 0; i < count; i++ {
        result += character
    }
    return result
}

func abs(x int) int {
    if x < 0 {
        return -x
    }
    return x
}

I didn't find any good solution to abs integer in go :(

Collapse
 
splinter98 profile image
splinter98

Very late to the party here, but wanted to post another python solution.

Takes advantage of using string formatting to center the text, simplifying the code, also using chain from itertools to stack to range functions together.

from itertools import chain


def diamond(size):
    if size < 0 or not (size % 2):
        return None
    star = (
        f"{'*'*l: ^{size}}"
        for l in chain(
            range(1, size, 2), range(size, 0, -2)
        )
    )
    return "\n".join(star)


if __name__ == "__main__":
    print(diamond(11))
Collapse
 
kvharish profile image
K.V.Harish

My solution in js


const padSpaceToSides = (str, len) => {
        const padlen = len - str.length,
          right = Math.ceil( padlen / 2 ),
          left = padlen - right;
        return str = Array(left+1).join(' ') + str + Array(right+1).join(' ');
      },
      diamondTopFormation = (end, atom) => {
        const start = 1, step = 2;
        for(let i = start; i < end; i += step) {
          console.log(padSpaceToSides(atom.repeat(i), end));
        }
      },
      diamondBottomFormation = (start, atom) => {
        const end = 1, step = 2;
        for(let i = start; i >= end; i -= step) {
          console.log(padSpaceToSides(atom.repeat(i), start));
        }
      },
      diamond = (height, atom = '*') => {
        if(height % 2 === 0 || height < 0) {
          return null;
        }
        diamondTopFormation(height, atom);
        diamondBottomFormation(height, atom);
      };

diamond(5);

Collapse
 
willsmart profile image
willsmart • Edited

JS

Now with contrast, invertability, custom strings and other completely unnecessary bells and whistles...

Collapse
 
vbarinov profile image
Vlad Barinov

Nice one!

Collapse
 
cvanpoelje profile image
cvanpoelje

That's amazing >_<

Collapse
 
nishikr profile image
Nishanth Kr

Couldnt find java one here. so uploading mine (suggestions are welcome)

if (base % 2 != 0 && base>0) {
int spaceDiff = (base / 2);
int star, row, order = 2;
// upper and middle
for (row = 0; row < base; row++) {
for (int space = spaceDiff; space > order - 2; space--) {
System.out.print(" ");
}
++order;
for (star = 0; star <= row; star++) {
System.out.print("");
}
System.out.println();
++row;
}
//bottom
order = spaceDiff;
for (row = base - 2; row > 0; row--) {
for (int space = order; space < spaceDiff + 1; space++) {
System.out.print(" ");
}
--order;
for (star = row; star > 0; star--) {
System.out.print("
");
}
System.out.println();
--row;
}
}

Collapse
 
anfossistudio profile image
AnfossiStudio

JavaScript

Collapse
 
iarmankhan profile image
Arman Khan

WOW! 😍

Collapse
 
coreyja profile image
Corey Alexander

Ahh you are 100% correct! I was confusing myself with Natural Numbers (which 0 is NOT), but that's unrelated to even/odd!

Good call out!

Collapse
 
nickytonline profile image
Nick Taylor

Late to the game here, but here you go, a JS implementation.

Collapse
 
riadulislam008 profile image
riadulIslam008 • Edited

Javascript

Collapse
 
riadulislam008 profile image
riadulIslam008

Javascript ans.