Construye un triángulo sin triángulos

44

Cuando era niño, me gustaba mucho jugar con estos juguetes:

ingrese la descripción de la imagen aquí

Probablemente pretendían que estos fueran utilizados para el arte, ¡pero yo siempre los usé para las matemáticas! Fractales, patrones, etc. Una vez, me dieron este desafío:

Construye un triángulo sin usar ninguno de los mosaicos de triángulos verdes.

Este desafío me dejó perplejo por mucho tiempo, hasta que me topé con una forma realmente hermosa y simple de hacerlo con solo 3 trapecios:

  /\  
 /_/\ 
/__\_\

Ahora, toma este triángulo y gíralo:

______         
\ \__/         
 \/ /          
  \/ 

Usando estos dos triángulos, podemos construir triángulos más grandes a partir de ellos. Aquí hay un triángulo de altura 2:

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

Y aquí hay triángulos de altura 3-7:

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

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

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

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

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

El reto

Escriba un programa o función que tome un número n e imprima un triángulo sin triángulo de altura n . Los espacios finales en cada línea son aceptables, y hasta una nueva línea final o inicial también es aceptable. IO puede estar en cualquier formato razonable. Se garantiza que la entrada sea un número entero positivo, por lo que no tiene que preocuparse por números negativos, decimales, no números, etc.

¡La respuesta más corta en bytes gana!

DJMcMayhem
fuente
Intenta hacer más trapecios con los trapecios. Las longitudes 2 y 3 son definitivamente posibles (y por extensión, todos los números de la forma 2 ^ a * 3 ^ b) (¿Cómo lo sé? Jugué con el mismo tipo de bloques cuando era niño)
CalculatorFeline
1
@CatsAreFluffy Bueno, como puedes hacer un trapezoide con triángulos, puedes concluir que puedes hacer trapezoides con trapezoides. De hecho, si observa los triángulos de altura 3 y 7, puede ver el mismo patrón repetido con trapecios grandes.
DJMcMayhem
Este desafío es realmente genial. Disfruté descubriendo cómo hacer esto en Retina.
mbomb007
@ mbomb007 ¡Me alegra saber que lo disfrutaste! = D Es exactamente por eso que escribo desafíos.
DJMcMayhem
2
Este desafío encaja perfectamente en la pantalla con la aplicación móvil. ¿Fue eso intencional? :)
Doddy

Respuestas:

15

CJam, 47

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

Explicación:

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

Pruébalo en línea

aditsu
fuente
17

Rubí, 79

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

A. (-4 bytes, -1 +1) cambió de 0-indexado ( .times) a 1-indexado ( 1.upto)

B. (-5 bytes) cambió de una matriz de tres cadenas de 6 caracteres a la selección de una subcadena de 6 caracteres de una cadena de 18 caracteres.

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

D. (-5 bytes) redujo las cinco barras invertidas dobles a barras diagonales simples (en parte posible gracias al reordenamiento de la cadena requerida para el punto A)

Rubí, 94

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

explicación

La unidad básica es un diamante 3x6 de la siguiente manera (último carácter en cada fila duplicado para mayor claridad :)

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

Todo lo que necesitamos hacer es mostrar una ventana adecuada de este patrón. Ruby's le ljustpermite rellenar con cualquier cadena, no solo espacios. Normalmente ljustse usaría para rellenar una cadena de caracteres imprimibles agregando espacios al final, pero aquí lo usamos al revés: para rellenar una cadena de espacios agregando caracteres imprimibles al final.

sin golf en el programa de prueba

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
fuente
@ mbomb007 Es la primera vez que tengo esa queja. Como ingeniero, estoy acostumbrado a hacer revisiones en todo. Este es un desafío bastante simple y las mejoras son bastante triviales, así que seguí adelante y eliminé las cartas de revisión. Creo que dejar el código original es bueno o al menos no hace daño, ya que es más fácil de seguir que la versión actual.
Level River St
3
El tamaño del código generalmente identifica de forma única cualquier revisión, pero el historial de revisiones también está disponible para cualquiera que vea el historial de edición.
mbomb007
9

Retina , 150 122 118 bytes

¡El resultado de este desafío se ve increíble, por cierto!

La entrada está en unario. La salida contiene un salto de línea final. El código usa la codificación ISO 8859-1. Tenga en cuenta el espacio final en la penúltima línea.

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

Pruébalo en línea

Explicación

Si desea una explicación más detallada, comente o envíeme un mensaje en el 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$* 

Gracias a Martin por jugar al golf con 32 bytes de descuento.

mbomb007
fuente
6

Lenguaje de impresión ascii de Tarmo, 46 ​​bytes. (no competidor)

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

Solo mirando lenguajes de programación tan extraños como CJam, me marea un poco lo complejo, antinatural y críptico que puede ser el lenguaje, que quería "ir audazmente a donde ningún hombre había ido antes" e inventar mi propio lenguaje. Como resultado, he creado mi propio lenguaje para la impresión de patrones ascii.

La idea básica es que puede definir primero el patrón y luego la impresión, utilizando el mismo tipo de carácter '1' o '2' o cualquier número, puede definir su propio patrón de impresión.

Una vez que se define el patrón (comienza desde el número hasta el final del número): los siguientes números ejecutarán la impresión del patrón.

Por ejemplo

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

Salidas como esta:

  /\
 /_/\
/__\_\

Definirá el patrón 1 y luego lo imprimirá de inmediato. El patrón se define todo separado con '|' personaje. 0 al final: actúa como la terminación del patrón.

Los caracteres especiales como '$' están reservados como avance de línea, y '~' está reservado para el espaciado, la mitad, de un patrón específico.

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

Will generará un texto como este:

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

Lo siguiente es for-loops. Ese debe ser fácilmente visible, por lo que he conservado {} corchetes para bucles for, pero los nombres de las variables se nombran automáticamente, por lo que el primer corchete usará 'a' variable, el segundo 'b' y así sucesivamente. La iteración siempre irá de 0 a un número específico, y ese número se define antes de {} paréntesis.

'n' es una variable reservada para la entrada de toda la función.

Entonces código:

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

Salidas de Will (con n == 4):

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

Y '#' es un modificador especial para recortar espacios en blanco de plomo.

Y finalmente toda la solución:

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
}

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

Will genera esto:

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
fuente
1
Eso es realmente asombroso! ¡Deberías poner eso en Github y alentar a las personas a usarlo!
DJMcMayhem
3
¡Bienvenido a Programming Puzzles y Code Golf! Es muy agradable que hayas inventado tu propio lenguaje de programación, pero ¿la última versión en la que se puede ejecutar es anterior al desafío?
Adnan
No te entendí completamente, ¿qué estás diciendo?
TarmoPikaro
Bueno, si el lenguaje en sí es más nuevo que el desafío, es común marcarlo como no competitivo (derecho bastante lógico;)). Esta podría ser una publicación relevante.
Adnan
El idioma depende del dominio del problema, y ​​no sabía que tal problema existía antes de leerlo desde aquí. Supongo que podría codificar el lenguaje antes si ya he encontrado un problema similar. :) De todos modos, al cosechar este sitio he entendido que CJam es un lenguaje bastante "normal" aquí. :)
TarmoPikaro
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`

Donde \nrepresenta el carácter literal de nueva línea. Si una línea n*3inicial con espacios y una nueva línea es aceptable, .slice(1)se puede eliminar para ahorrar 9 bytes.

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

El principio es muy similar al de otras respuestas: toma tres cadenas repetidas y luego colócalas de tal manera que solo necesites recortar algunas de ellas para obtener el triángulo, luego colócalas a la izquierda.

wvxvw
fuente
2

C ++, 395 bytes

Código de golf por primera vez con un tamaño glorioso de 395 bytes en C ++. En mi caso, se siente un poco como un concurso de ofuscación: 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 HK
fuente