Build a triangle without any triangles

43

5

As a little kid, I liked to play with these toys a lot:

enter image description here

They probably intended for these to be used for art, but I always used them for math! Fractals, patterns, etc. One time, I was given this challenge:

Build a triangle without using any of the green triangle tiles.

This challenge stumped me for the longest time, until I stumbled upon a really beautiful and simple way to do it with just 3 trapezoids:

  /\  
 /_/\ 
/__\_\

Now, take this triangle, and rotate it:

______         
\ \__/         
 \/ /          
  \/ 

Using these two triangles, we can construct larger triangles out of them. Here is a triangle of height 2:

     /\           
    /_/\          
   /__\_\         
  /\ \__/\        
 /_/\/ /_/\       
/__\_\/__\_\    

And here are triangles of height 3-7:

#3
        /\
       /_/\
      /__\_\
     /\ \__/\
    /_/\/ /_/\
   /__\_\/__\_\
  /\ \__/\ \__/\
 /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\

#4
           /\
          /_/\
         /__\_\
        /\ \__/\
       /_/\/ /_/\
      /__\_\/__\_\
     /\ \__/\ \__/\
    /_/\/ /_/\/ /_/\
   /__\_\/__\_\/__\_\
  /\ \__/\ \__/\ \__/\
 /_/\/ /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\/__\_\

#5
              /\
             /_/\
            /__\_\
           /\ \__/\
          /_/\/ /_/\
         /__\_\/__\_\
        /\ \__/\ \__/\
       /_/\/ /_/\/ /_/\
      /__\_\/__\_\/__\_\
     /\ \__/\ \__/\ \__/\
    /_/\/ /_/\/ /_/\/ /_/\
   /__\_\/__\_\/__\_\/__\_\
  /\ \__/\ \__/\ \__/\ \__/\
 /_/\/ /_/\/ /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\/__\_\/__\_\

#6
                 /\
                /_/\
               /__\_\
              /\ \__/\
             /_/\/ /_/\
            /__\_\/__\_\
           /\ \__/\ \__/\
          /_/\/ /_/\/ /_/\
         /__\_\/__\_\/__\_\
        /\ \__/\ \__/\ \__/\
       /_/\/ /_/\/ /_/\/ /_/\
      /__\_\/__\_\/__\_\/__\_\
     /\ \__/\ \__/\ \__/\ \__/\
    /_/\/ /_/\/ /_/\/ /_/\/ /_/\
   /__\_\/__\_\/__\_\/__\_\/__\_\
  /\ \__/\ \__/\ \__/\ \__/\ \__/\
 /_/\/ /_/\/ /_/\/ /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\/__\_\/__\_\/__\_\

#7
                    /\
                   /_/\
                  /__\_\
                 /\ \__/\
                /_/\/ /_/\
               /__\_\/__\_\
              /\ \__/\ \__/\
             /_/\/ /_/\/ /_/\
            /__\_\/__\_\/__\_\
           /\ \__/\ \__/\ \__/\
          /_/\/ /_/\/ /_/\/ /_/\
         /__\_\/__\_\/__\_\/__\_\
        /\ \__/\ \__/\ \__/\ \__/\
       /_/\/ /_/\/ /_/\/ /_/\/ /_/\
      /__\_\/__\_\/__\_\/__\_\/__\_\
     /\ \__/\ \__/\ \__/\ \__/\ \__/\
    /_/\/ /_/\/ /_/\/ /_/\/ /_/\/ /_/\
   /__\_\/__\_\/__\_\/__\_\/__\_\/__\_\
  /\ \__/\ \__/\ \__/\ \__/\ \__/\ \__/\
 /_/\/ /_/\/ /_/\/ /_/\/ /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\/__\_\/__\_\/__\_\/__\_\

The Challenge

Write a program or function that takes a number n and prints a triangle-less triangle of height n. Trailing spaces on each line is acceptable, and up to one trailing or leading newline is also acceptable. IO can be in any reasonable format. The input is guarenteed to be a positive integer, so you don't have to worry about negative numbers, decimals, non-numbers etc.

Shortest answer in bytes wins!

James

Posted 2016-04-14T15:22:09.627

Reputation: 54 537

Try making more trapezoids out of the trapezoids. Lengths 2 and 3 are definitely possible (and by extension, all numbers of the form 2^a*3^b) (How do I know? Played with the same kind of blocks when I was a kid.) – CalculatorFeline – 2016-04-14T16:28:29.733

1@CatsAreFluffy Well, since you can make a trapezoid out of triangles, you can conclude that you can make trapezoids out of trapezoids. In fact, if you look at the triangles of height 3 and 7, you can kinda see the same pattern repeated with large trapezoids. – James – 2016-04-14T16:39:25.217

This challenge is really cool. I enjoyed figuring out how to do this in Retina. – mbomb007 – 2016-04-14T21:55:27.253

@mbomb007 Glad to hear you enjoyed it! =D That's exactly why I write challenges. – James – 2016-04-14T21:56:45.390

2This challenge fits perfectly on the screen with the mobile app. Was that intentional? :) – Doddy – 2016-04-16T09:54:02.400

I wonder if there's a way to make the larger triangles without using any of the smaller triangles... – 2012rcampion – 2016-04-16T14:49:14.497

Answers

15

CJam, 47

ri_"/__\_\/_/\/ /\ \__"6/f**eeW%{_S.*s\~,\-<N}/

Explanation:

ri_       read the input, convert to integer and duplicate
"…"       push that string, containing the repeating pattern
           (3 lines in reverse order, concatenated)
6/        split into (3) lines of 6 characters
f*        multiply (repeat) each line n times
*         repeat the array of 3 lines n times
           at this point we have an array of 3*n strings with 6*n characters each
ee        enumerate the array (obtaining an array of [index string] pairs)
W%        reverse the array
           (so the lines are in correct order and indices in reverse order)
{…}/      for each [index string] pair
  _       duplicate the pair
  S.*     vectorized-multiply with " "
           this effectively replaces the index with a string of <index> spaces
  s       convert the pair to string, effectively concatenating the spaces
           with the string
  \       swap with the other copy of the [index string] pair
  ~,      dump the index and string on the stack and get the string length
  \-      subtract the index from it - this is the desired line length
  <       cut the concatenated string to that length
  N       add a newline

Try it online

aditsu quit because SE is EVIL

Posted 2016-04-14T15:22:09.627

Reputation: 22 326

17

Ruby, 79

->n{1.upto(n*=3){|i|puts (' '*(n-i)).ljust(n+i,'/__\_\/\ \__/_/\/ '[i%3*6,6])}}

A. (-4 bytes, -1 +1) changed from 0-indexed (.times) to 1-indexed (1.upto)

B. (-5 bytes) changed from array of three 6-char strings to selection of 6-char substring of 18-char string.

C. (-1 byte) m=n*3 -> n*=3

D. (-5 bytes) reduced all five double backslashes to single backslashes (partly made possible by reordering of string required for point A)

Ruby, 94

->n{(m=n*3).times{|i|puts (' '*(m-i-1)).ljust(m+i+1,[ '/\\ \\__','/_/\\/ ','/__\\_\\'][i%3])}}

explanation

The basic unit is a 3x6 diamond as follows (last character on each row duplicated for clarity:)

    /\ \__/
   /_/\/ / 
  /__\_\/

All we need to do is display a suitable window of this pattern. Ruby's ljust allows you to pad with any string, not just spaces. Normally ljust would be used to pad a string of printable characters by adding spaces at the end, but here we use it in reverse: to pad a string of spaces by adding printable characters at the end.

ungolfed in test program

f=->n{
  (m=n*3).times{|i|                  #for each line of the triangle
    puts (' '*(m-i-1)).              #print m-i-1 spaces, 
      ljust(m+i+1,[ '/\\ \\__',      #left justified and padded to total length m+i+1
                   '/_/\\/ ',        #by one of these three strings
                  '/__\\_\\'][i%3])
  }
}

f[gets.to_i]

Level River St

Posted 2016-04-14T15:22:09.627

Reputation: 22 049

@mbomb007 It's the first time I've had that complaint. As an engineer, I'm used to putting revisions on everything This is a fairly simple challenge and the improvements are quite trivial, so I've gone ahead and deleted the revision letters.I think leaving the original code up is good or at least does no harm, as it's easier to follow than the current version. – Level River St – 2016-04-14T20:22:14.057

3The code size usually uniquely identifies any revision, but the revision history is also available for anyone viewing the edit history. – mbomb007 – 2016-04-14T20:55:49.837

9

Retina, 150 122 118 bytes

The output to this challenge looks awesome, by the way!

Input is in unary. The output contains a trailing linefeed. The code uses ISO 8859-1 encoding. Note the trailing space on the penultimate line.

(?=_\\¶.*1)
_\/__\
(?=/_/\\¶.*1)
/_/\/ 
(^|__)(?=/\\¶.*1)
$1/\ \__
ms}`(.*1*)1
/\¶/_/\¶/__\_\¶$1
m`^(?=(.*¶)*.)
$#1$* 

Try it online

Explanation

If you want a more in-depth explanation, comment or message me in chat.

(?=_\\¶.*1)                     # Matches the start of the 3rd line of every triangle
/__\_\                          #   and prepends another layer if needed
(?=/_/\\¶.*1)                   # 2nd line of each triangle
/_/\/ 
(^|__)(?=/\\¶.*1)               # 1st line of each triangle
$1/\ \__
ms}`(.*1*)1                 # This and above in a multi-single-line loop.
/\¶/_/\¶/__\_\¶$1               #   This stage adds a flattened triangle on top
m`^(?=(.*¶)*.)                  # Prepend a space for every line following -1
$#1$* 

Thanks to Martin for golfing 32 bytes off.

mbomb007

Posted 2016-04-14T15:22:09.627

Reputation: 21 944

6

Tarmo's ascii printing language, 46 bytes. (non-competing)

1  /\| /_/\|/__\_\2 \__|/ 0n{n-a-1{~}1a{2#1}$}

Just by looking to such odd programming languages like CJam, it's makes me bit dizzy how complex, unnatural and cryptic language can be, that I wanted to "boldly go where no man has gone before", and invent my own language. As a result I've created my own language for ascii patterns printing.

Basic idea is that you can define first patten and then printing - using same kind of character '1' or '2' or whatever number - you can define your own print pattern.

Once pattern is defined (Starts from number till number end) - next numbers will execute pattern printing.

For example

1  /\| /_/\|/__\_\01

Outputs like this:

  /\
 /_/\
/__\_\

Will define pattern 1 and then print it right away. Pattern is defined everything separated with '|' character. 0 at the end - acts like pattern termination.

Special characters like '$' are reserved as line-feed, and '~' is reserved for spacing - half - of specific pattern.

1  /\| /_/\|/__\_\01$~11$~1~11

Will outputs text like this:

  /\
 /_/\
/__\_\
     /\
    /_/\
   /__\_\
        /\
       /_/\
      /__\_\

Next goes for-loops. That one needs to be easily visible - so I've retained {} brackets for for-loops, but variable names are auto-named - so first bracket will use 'a' variable, second 'b' and so on. Iteration will go always from 0 to specific number - and that number is defined before {} brackets.

'n' is reserved variable for whole function input.

So code:

1  /\| /_/\|/__\_\0n{1$}

Will outputs ( With n == 4 ):

  /\
 /_/\
/__\_\
  /\
 /_/\
/__\_\
  /\
 /_/\
/__\_\
  /\
 /_/\
/__\_\

And '#' is special modifier for trim lead whitespace.

And finally whole solution:

DrawPatterns.cs:

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.CSharp;

class DrawPatterns
{
//Command line parameters - for example like this: "1  /\| /_/\|/__\_\2 \__|/ 0n{n-a-1{~}1a{2#1}$}" 3
    static Dictionary<char, String[]> patterns = new Dictionary<char,string[]>();

    static string Tabs(int n)
    {
        if( n < 0 ) n = 0;

        String r = "";

        for( int i = 0; i < n ; i++ )
            r += "    ";

        return r;
    }

    static int[] left = new int[10];
    static int top = Console.CursorTop;
    static int lastTop = Console.CursorTop;

    static public void DoPrint(char c, char modifier = ' ')
    {
        if (c == '$')
        {
            for (int i = 0; i < left.Length; i++)
                left[i] = 0;
            top = lastTop + 1;
            return;
        }

        if (!patterns.ContainsKey(c))
            return;

        if (modifier == '½' || modifier == '~')
        {
            int maxSize = patterns[c].Select(x => x.Length).Max();
            for( int i = 0; i < left.Length; i++ )
                left[i] += maxSize / 2;
            return;
        }

        int iLine = 0;
        foreach (var l in patterns[c])
        {
            Console.SetCursorPosition(left[iLine], top + iLine);
            if( top + iLine > lastTop ) 
                lastTop = top + iLine;

            String s = l;
            if (modifier == '#')
                s = s.TrimStart(' ');

            Console.WriteLine(s);
            left[iLine] += s.Length;
            iLine++;
        }
    }

    static void Main(string[] _args)
    {
        List<String> args = _args.ToList();
        String todo = "";
        String code = "";
        char nextVar = 'a';
        String lf = "\r\n";
        int align = 1;
        char lastModifier = ' ';
        int nextArg = 1;
        Dictionary<String, String> argValues = new Dictionary<string,string>();
        bool bDebug = false;

        if (args.Count != 0 && args[0].ToLower() == "-d")
        {
            bDebug = true;
            args.RemoveAt(0);
        }

        if (args.Count == 0)
        {
            Console.WriteLine("Usage: DrawPatterns.cs [options] \"script\" <arguments to script>");
            Console.WriteLine("[options] allowed:");
            Console.WriteLine("-d - debug");
            return;
        }

        String prog = args[0];

        for( int i = 0; i < prog.Length; i++ )
        {
            char c = prog[i];

            // Define pattern.
            if (c >= '0' && c <= '9' && !patterns.ContainsKey(c))
            {
                String p = Regex.Match(prog.Substring(i + 1), "[^0-9]*").Groups[0].Value;
                patterns[c] = p.Split('|');
                i += p.Length;
                if( prog[i + 1] == '0' ) i++;
                continue;
            }

            String procRemain = prog.Substring(i);
            // modifier specified, but pattern number is not provided - use first pattern.
            if( lastModifier != ' ' && ( c < '0' || c > '9' ) )
            {
                code += Tabs(align);
                code += "print('1' , '" + lastModifier + "');" + lf;
                lastModifier = ' ';
            }

            switch ( c )
            {
                case '{':
                    code += Tabs(align);
                    code += "for ( int " + nextVar + " = 0; " + nextVar + " < " + todo + " ; " + nextVar + "++ )" + lf;

                    //  Check for all variable names if they can be used in program.
                    foreach ( var m in Regex.Matches(todo, "[a-zA-Z_][a-zA-Z0-9_]*", RegexOptions.Singleline) )
                    {
                        String varName = m.ToString();

                        if( varName.Length == 1 && varName[0] <= nextVar )
                            // Already declared as a loop.
                            continue;

                        if( argValues.ContainsKey(varName ) )
                            continue;

                        if( nextArg >= args.Count )
                        {
                            Console.WriteLine("Insufficient parameters provided to script - argument '" + varName + "' value is needed");
                            return;
                        }

                        argValues[varName] = args[nextArg];
                        nextArg++;
                    }


                    code += Tabs(align);
                    code += "{" + lf;
                    nextVar++;
                    todo = "";
                    align++;
                    break;

                case '}':
                    align--;
                    code += Tabs(align);
                    code += "}" + lf;
                    break;

                default:
                    if (((c >= '0' && c <= '9') || c == '<' || c == '$') && todo == "")
                    {
                        code += Tabs(align);
                        code += "print('" + c + "' , '" + lastModifier + "');" + lf;
                        lastModifier = ' ';
                        continue;
                    }

                    if (c == '½' || c == '~' || c == '#')
                    {
                        lastModifier = c;
                        continue;
                    }

                    if( c == '\r' || c == '\n' )
                        continue;

                    todo += c;
                    break;
            }

        } //for

        String code2 = "";
        code2 += "using System;" + lf;
        code2 += "public class ExecClass { static void Exec( Action<char, char> print";

        object[] invokeArgs = new object[ argValues.Count+1];
        invokeArgs[0] = new Action<char, char>(DoPrint);
        int iValueIndex = 1;

        foreach ( var kv in argValues )
        {
            code2 += ",";
            code2 += "int " + kv.Key;
            invokeArgs[iValueIndex] = Int32.Parse(kv.Value);
            iValueIndex++;
        }

        code2 += ") {" + lf;
        code2 += code;
        code2 += "} };";

        if( bDebug )
        {
            int line = 1;
            String lineNumberedCode =Regex.Replace(code2, "^(.*)$", 
                delegate(Match m) { return (line++).ToString("d2") + ": " + m.Value; },
                RegexOptions.Multiline
            );
            Console.WriteLine(lineNumberedCode);
            Console.WriteLine();
            Console.WriteLine();
        }

        left[0] = Console.CursorLeft;
        for( int i = 1; i < left.Length; i++ )
            left[i] = left[0];
        top = Console.CursorTop;

        try
        {
            var compileResult = new CSharpCodeProvider().CompileAssemblyFromSource( new CompilerParameters() { GenerateExecutable = false, GenerateInMemory = true }, code2);
            if (compileResult.Errors.HasErrors)
            {
                foreach (CompilerError ce in compileResult.Errors)
                {
                    if (ce.IsWarning) continue;
                    Console.WriteLine("{0}({1},{2}: error {3}: {4}", ce.FileName, ce.Line, ce.Column, ce.ErrorNumber, ce.ErrorText);
                }
                return;
            }

            var method = compileResult.CompiledAssembly.GetType("ExecClass").GetMethod("Exec", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
            method.Invoke(null, invokeArgs);

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        Console.SetCursorPosition(1, lastTop);
        Console.WriteLine();
        Console.WriteLine();
    } //Main
}

With command line arguments like this: -d "1 /\| /_/\|/___\2 __|/ 0n{n-a-1{½}1a{2#1}$}" 3

Will outputs this:

01: using System;
02: public class ExecClass { static void Exec( Action<char, char> print,int n) {
03:     for ( int a = 0; a < n ; a++ )
04:     {
05:         for ( int b = 0; b < n-a-1 ; b++ )
06:         {
07:             print('1' , '~');
08:         }
09:         print('1' , ' ');
10:         for ( int c = 0; c < a ; c++ )
11:         {
12:             print('2' , ' ');
13:             print('1' , '#');
14:         }
15:         print('$' , ' ');
16:     }
17: } };


        /\
       /_/\
      /__\_\
     /\ \__/\
    /_/\/ /_/\
   /__\_\/__\_\
  /\ \__/\ \__/\
 /_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\

TarmoPikaro

Posted 2016-04-14T15:22:09.627

Reputation: 161

1That's really awesome! You should put that up on Github and encourage people to use it! – James – 2016-04-16T08:23:22.423

3Welcome to Programming Puzzles and Code Golf! It is very nice that you invented your own programming language, but does the latest version in which it can be run predate the challenge? – Adnan – 2016-04-16T08:23:51.840

Did not fully understood you, what are you saying ? – TarmoPikaro – 2016-04-16T19:14:13.713

Well, if the language itself is newer than the challenge, it is common to mark it as non-competing (pretty logical right ;)). This might be a relevant post.

– Adnan – 2016-04-16T23:50:09.073

Language depends on problem domain, and I didn't know such problem existed before I've read it from here. I'll guess I've could code language earlier if I've hit similar problem already. :) Anyway, by harvesting this site I've understood that CJam is quite "normal" language in here. :) – TarmoPikaro – 2016-04-17T06:14:26.283

@TarmoPikaro If you would allow languages that are newer than the challenge then every challenge could get a 0 byte solution where the language's default output will be exactly the output the challenge requires. – David Mulder – 2016-04-17T15:21:46.630

Solution which is targetted only for one problem is not a good solution. (abstraction is missing, solution is one problem solution.) Unless problem is AI - not a good solution. But you must understand that problem driven solution is normally better than generic solution - because it maps to problem domain better. Sql was probably created starting from one problem - you have to start from somewhere?! Such domain based solutions tends to extract use cases, which is good. – TarmoPikaro – 2016-04-17T17:49:19.643

That's why we disqualify entries using languages or features that were added after the challenge was created. – mbomb007 – 2016-04-18T14:55:50.487

Also, you need to post a link to the github or an interpreter for this language. If no interpreter exists, then this answer is not valid. – mbomb007 – 2016-04-18T14:57:11.243

Is C# script ok for you: http://www.csscript.net/ ? I guess it's runs in windows, should be theoretically portable to any os, but I haven't tested by myself.

– TarmoPikaro – 2016-04-18T21:40:51.790

5

JavaScript (ES6), 119 bytes

n=>`,/\\ \\__,/_/\\/ ,/__\\_\\`[r=`repeat`](n).split`,`.map((s,i)=>` `[r](n*3-i)+s[r](n).slice(0,i*2)).slice(1).join`\n`

Where \n represents the literal newline character. If a leading line with n*3 spaces and a newline is acceptable then the .slice(1) can be removed for a saving of 9 bytes.

Neil

Posted 2016-04-14T15:22:09.627

Reputation: 95 035

3

Python 2, 118 bytes

def f(n,s=["/\\ \\__","/_/\\/ ","/__\\_\\"]):
 print'\n'.join(map(lambda x:' '*(n*3-x)+(n*s[x%3])[:x*2+2],range(n*3)))

Similar approach to Level River St's Ruby answer.

Try it online

Mr Public

Posted 2016-04-14T15:22:09.627

Reputation: 669

2

Python 2, 142 bytes

def f(n,m):return f(n-1,m+3)+[' '*(m+x)+(y*n)[x*2:]for x,y in((2,' \\__/\\'),(1,'/ /_/\\'),(0,'/__\\_\\'))]if n else[]
print '\n'.join(f(n,0))

The principle is very similar to other answers: take three repeated strings and then layer them in such a way that you only need to trim some of them to get the triangle, then pad them on the left.

wvxvw

Posted 2016-04-14T15:22:09.627

Reputation: 151

2

C++, 395 Bytes

First time code golf with a glorious size of 395 bytes in C++. In my case, it feels a little like a contest for obfuscation : D

#include <iostream>
#include <cstring>
#define A for (int k=0;k<((s-(i+1))*3+(2-j));k++) cout<<" ";
using namespace std; string t[3]={"/\\","/_/\\","/__\\_\\"};string r[2]={" \\__","/ "};int tr=3;int main(int,char**argv){int s=atoi(argv[1]);for(int i=0;i<s;i++){for(int j=0;j<tr;j++){A for(int l=1;l<=2*(i+1)-1;l++){if((l%2)==0&&(j<2)){cout<<r[j];}else if ((l%2)==1)cout<<t[j];}A cout<<endl;}}}

John H. K.

Posted 2016-04-14T15:22:09.627

Reputation: 121

0

Pyth, 66 bytes

jmj+L**3-Qhd\ [+*2;j" \\__"*Jhd]"/\\"+;j"/ "*J]"/_/\\"*J"/__\\_\\"

Try it online!

Leaky Nun

Posted 2016-04-14T15:22:09.627

Reputation: 45 011