Construa um triângulo sem triângulos


44

Quando criança, eu gostava muito de brincar com esses brinquedos:

insira a descrição da imagem aqui

Eles provavelmente pretendiam que eles fossem usados ​​para arte, mas eu sempre os usei para matemática! Fractais, padrões, etc. Certa vez, recebi este desafio:

Construa um triângulo sem usar nenhum dos blocos de triângulo verdes.

Esse desafio me surpreendeu por mais tempo, até me deparar com uma maneira realmente bonita e simples de fazer isso com apenas três trapézios:

  /\  
 /_/\ 
/__\_\

Agora, pegue este triângulo e gire-o:

______         
\ \__/         
 \/ /          
  \/ 

Usando esses dois triângulos, podemos construir triângulos maiores a partir deles. Aqui está um triângulo de altura 2:

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

E aqui estão triângulos de altura 3-7:

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

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

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

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

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

O desafio

Escreva um programa ou função que use um número n e imprima um triângulo sem triângulo da altura n . Os espaços à direita em cada linha são aceitáveis ​​e até uma nova linha à direita ou à direita também é aceitável. O IO pode estar em qualquer formato razoável. A entrada é garantida como um número inteiro positivo, para que você não precise se preocupar com números negativos, decimais, não números, etc.

Menor resposta em bytes ganha!


Tente fazer mais trapézios com os trapézios. Os comprimentos 2 e 3 são definitivamente possíveis (e, por extensão, todos os números do formato 2 ^ a * 3 ^ b) (como eu sei? Joguei com o mesmo tipo de bloco quando eu era criança.)
CalculatorFeline

1
@CatsAreFluffy Bem, como você pode fazer um trapézio a partir de triângulos, pode concluir que você pode fazer trapézios a partir de trapézios. De fato, se você observar os triângulos de altura 3 e 7, poderá ver o mesmo padrão repetido com grandes trapézios.
DJMcMayhem

Esse desafio é muito legal. Eu gostei de descobrir como fazer isso na Retina.
mbomb007

@ mbomb007 Fico feliz em saber que você gostou! = D É exatamente por isso que escrevo desafios.
DJMcMayhem

2
Esse desafio se encaixa perfeitamente na tela com o aplicativo móvel. Isso foi intencional? :)
Doddy

Respostas:


15

CJam, 47

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

Explicação:

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

Experimente online


17

Ruby, 79

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

A. (-4 bytes -1 +1) alterado de 0-indexado ( .times) para 1-indexado ( 1.upto)

B. (-5 bytes) alterado da matriz de três seqüências de caracteres de 6 caracteres para a seleção de substring de 6 caracteres da sequência de 18 caracteres.

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

D. (-5 bytes) reduziu todas as cinco barras invertidas duplas para barras invertidas simples (parcialmente possibilitadas pela reordenação da string necessária para o ponto A)

Ruby, 94

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

explicação

A unidade básica é um diamante 3x6 da seguinte forma (último caractere em cada linha duplicado para maior clareza :)

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

Tudo o que precisamos fazer é exibir uma janela adequada desse padrão. O Ruby's ljustpermite que você use qualquer corda, não apenas espaços. Normalmente, ljustseria usado para preencher uma sequência de caracteres imprimíveis adicionando espaços no final, mas aqui usamos o contrário: para preencher uma sequência de espaços adicionando caracteres imprimíveis no final.

ungolfed no programa de teste

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]

@ mbomb007 É a primeira vez que recebo essa reclamação. Como engenheiro, estou acostumado a fazer revisões em tudo. Esse é um desafio bastante simples e as melhorias são bastante triviais, por isso fui adiante e excluí as cartas de revisão. Acho que deixar o código original é bom ou pelo menos não faz mal, pois é mais fácil de seguir do que a versão atual.
Level River St

3
O tamanho do código geralmente identifica exclusivamente qualquer revisão, mas o histórico de revisões também está disponível para qualquer pessoa que esteja visualizando o histórico de edições.
mbomb007

9

Retina , 150 122 118 bytes

A saída para este desafio parece incrível, a propósito!

A entrada está unária. A saída contém um avanço de linha à direita. O código usa a codificação ISO 8859-1. Observe o espaço à direita na penúltima linha.

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

Experimente online

Explicação

Se você quiser uma explicação mais aprofundada, comente ou me envie uma mensagem no 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$* 

Obrigado a Martin por jogar 32 bytes de desconto.


6

Linguagem de impressão ASCII da Tarmo, 46 ​​bytes. (não concorrente)

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

Só de olhar para linguagens de programação tão estranhas como CJam, fico um pouco tonto com o quão complexa, antinatural e enigmática pode ser, que eu queria "ir ousadamente aonde nenhum homem foi antes" e inventar minha própria linguagem. Como resultado, criei meu próprio idioma para a impressão de padrões ascii.

A idéia básica é que você possa definir primeiro padrão e depois imprimir - usando o mesmo tipo de caractere '1' ou '2' ou qualquer outro número - você pode definir seu próprio padrão de impressão.

Depois que o padrão é definido (inicia do número até o final do número) - os próximos números executam a impressão do padrão.

Por exemplo

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

Saídas como esta:

  /\
 /_/\
/__\_\

Irá definir o padrão 1 e depois imprimi-lo imediatamente. Padrão é definido tudo separado por '|' personagem. 0 no final - atua como finalização de padrão.

Caracteres especiais como '$' são reservados como avanço de linha e '~' é reservado para espaçamento - metade - de padrão específico.

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

Will produz texto como este:

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

Em seguida, vai para loops. Esse precisa estar facilmente visível - então, retirei {} colchetes para for-loops, mas os nomes de variáveis ​​são nomeados automaticamente - portanto, o primeiro colchete usará a variável 'a', o segundo 'b' e assim por diante. A iteração sempre passa de 0 a um número específico - e esse número é definido antes dos {} colchetes.

'n' é uma variável reservada para toda a entrada da função.

Então codifique:

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

Saídas Will (com n == 4):

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

E '#' é um modificador especial para o espaço em branco do eletrodo de compensação.

E finalmente a solução completa:

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
}

Com argumentos de linha de comando como este: -d "1 / \ | / _ / \ | / ___ \ 2 __ | / 0n {na-1 {½} 1a {2 # 1} $}" 3

O resultado será:

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: } };


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

1
Isso é realmente incrível! Você deve colocar isso no Github e incentivar as pessoas a usá-lo!
DJMcMayhem

3
Bem-vindo à Programação de Puzzles e Code Golf! É muito bom que você tenha inventado sua própria linguagem de programação, mas a versão mais recente na qual ela pode ser executada é anterior ao desafio?
Adnan

Não o entendi completamente, o que você está dizendo?
TarmoPikaro

Bem, se o idioma em si é mais novo que o desafio, é comum marcá-lo como não competitivo (bastante lógico;)). Esta pode ser uma publicação relevante.
Adnan

O idioma depende do domínio do problema, e eu não sabia que esse problema existia antes de ler aqui. Eu acho que eu poderia codificar a linguagem mais cedo, se já tiver encontrado um problema semelhante. :) De qualquer forma, ao coletar este site, entendi que o CJam é uma linguagem bastante "normal" aqui. :)
TarmoPikaro 17/04

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`

Onde \nrepresenta o caractere literal de nova linha. Se uma linha inicial com n*3espaços e uma nova linha for aceitável, ela .slice(1)poderá ser removida para salvar 9 bytes.



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))

O princípio é muito parecido com outras respostas: pegue três cordas repetidas e as coloque em camadas de forma que você só precise aparar algumas delas para obter o triângulo, depois coloque-as à esquerda.


2

C ++, 395 bytes

Primeiro código de golfe com um tamanho glorioso de 395 bytes em C ++. No meu caso, parece um pouco como um concurso de ofuscação: 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;}}}

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.