Imprimir un diamante ASCII -- java campo con console camp codereview Relacionados El problema

Print an ASCII diamond


31
vote

problema

Español

Esto requiere un ancho especificado por el usuario e imprime un diamante de ese ancho. Utiliza solo tres for Bucles, pero ¿podría reducir aún más? ¿Hay una solución más elegante?

  public class Diamond {      static boolean cont = true;      public static void main (String[] args) {         Scanner input = new Scanner(System.in);         while (cont) {             System.out.print("Width: ");             int width = input.nextInt();             int lines = width;             System.out.println();             for (int line = 0; line < lines; line++) {                 for (int spaces = 0; spaces < Math.abs(line - (lines / 2)); spaces++) {                     System.out.print(" ");                 }                 for (int marks = 0; marks < width - 2 * (Math.abs(line - (lines / 2))); marks++) {                     System.out.print("x");                 }                        System.out.println();             }             System.out.println();         }     } }   
Original en ingles

This takes a width specified by user and prints a diamond of that width. It uses only three for loops, but could I reduce that further? Is there a more elegant solution?

public class Diamond {      static boolean cont = true;      public static void main (String[] args) {         Scanner input = new Scanner(System.in);         while (cont) {             System.out.print("Width: ");             int width = input.nextInt();             int lines = width;             System.out.println();             for (int line = 0; line < lines; line++) {                 for (int spaces = 0; spaces < Math.abs(line - (lines / 2)); spaces++) {                     System.out.print(" ");                 }                 for (int marks = 0; marks < width - 2 * (Math.abs(line - (lines / 2))); marks++) {                     System.out.print("x");                 }                        System.out.println();             }             System.out.println();         }     } } 
     

Lista de respuestas

27
 
vote

Hay algunas cosas que podemos hacer para limpiar esto.

  • Esto es algo que extraería a su propio método. Manija Obtenga la entrada del usuario en el método main() , y luego pase al método 9988776665544338 .

  • su for Los bucles se dividen en iteración sobre líneas, espacios y marcas. Podemos simplificar eso a las filas y columnas simplemente donde podamos iterar sobre cada unidad individual a la vez. Esto también eliminará uno de sus 99887766655443310 S en el método final.

  • Podemos simplificar las matemáticas de dónde imprimir una pieza del diamante.

      Map() ++ Some((k,v)) == Map((k,v))1  

Método final:

  Map() ++ Some((k,v)) == Map((k,v))2  
 

There are a few things that we can do to clean this up.

  • This is something I would extract to its own method. Handle getting the user input in the main() method, and then pass that on to the drawDiamond() method.

  • Your for loops are divided into iterating over lines, spaces, and marks. We can simplify that down to just rows and columns where we can iterate over each individual unit at a time. This will also eliminate one of your System.out.println()s in the final method.

  • We can simplify down the math of where to print a piece of the diamond.

    if ((column == Math.abs(row - half)) || (column == (row + half)) || (column == (sqr - row + half - 1))) 

Final Method:

void drawDiamond(int sqr) {     int half = sqr/2;     for (int row=0; row<sqr; row++)     {         for (int column=0; column<sqr; column++)         {             if ((column == Math.abs(row - half)) || (column == (row + half)) || (column == (sqr - row + half - 1)))             {                 System.out.print("*");             }             else System.out.print(" ");         }         System.out.println();     } } 
 
 
20
 
vote

Sabes, es bueno ver el código que hace lo que dice, y una buena tarea simple que aún requiere algún rasguño de la cabeza ... pero asumiré que eres un principiante de Java.

Conceptos básicos

pasando por algunas de las cosas básicas ...

  • TIENE EL CÓDIGO 9988776655544330 Declarado como una variable estática fuera del método, pero el único lugar que se usa está dentro del método. En este caso, debe mover la declaración dentro del método main . Además, nada cambia ese estado, por lo que el programa solo corre, y ejecuta, que está bien (como un principiante).
  • No cierre el escáner input . Nuevamente, esto es probablemente porque el programa nunca se completa, pero hay buenas formas en Java7 para asegurarse de que suceda cuidadosamente, y sin mucho esfuerzo.
  • probablemente debería validar la entrada del usuario. Si el usuario entra en enteros negativos, en realidad está bien (el programa no hace nada). Más concerniente es si el usuario ingresa a 2000000000. Debe establecer un límite superior.
  • Llamas a esta forma un 'diamante' pero en realidad es un cuadrado. El ancho y la altura son el mismo número de caracteres. Solo necesita una variable, lines3 o width , no ambos.
  • Es confuso que tiene ambos line y lines variable. No hay necesidad de lines Si usa width , así que deshágase de él (también, ya que el indicador de usuario es "Ancho:").

OK, eso es unas cosas relativamente simples. Metiendo su código alrededor del uso de las sugerencias anteriores que recibo:

  public static void main (String[] args) {     boolean cont = true;      try (Scanner input = new Scanner(System.in)) {         while (cont) {             System.out.print("Width: ");             int width = input.nextInt();             System.out.println();              if (width > 100) {                 System.out.println("Width too wide, reducing to 100");                 width = 100;             }              for (int line = 0; line < width; line++) {                 for (int spaces = 0; spaces < Math.abs(line - (width / 2)); spaces++) {                     System.out.print(" ");                 }                 for (int marks = 0; marks < width - 2 * (Math.abs(line - (width / 2))); marks++) {                     System.out.print("x");                 }                        System.out.println();             }             System.out.println();         }     } }   

Algoritmo

OK, ahora, algunas cosas algorítmicas:

  • main0 y el main1 Las variantes son realmente lentas. Llamarlos desde el interior de los bucles es un problema real para el rendimiento, y es un mal hábito de aprender. Estos métodos bloquean la salida de la consola, y tampoco son agradables con otros hilos. Donde sea posible, siempre debe lote la impresión del personaje en una declaración más grande.
  • a veces, tomar las cosas es más fácil que agregarlo ... (Sugerencia críptica).

Podemos resolver mucha complejidad en sus bucles haciendo un par de trucos. Aquí hay una sugerencia:

  1. construye dos cuerdas, uno de los espacios y el otro de los caracteres 'x'. Cada uno debe ser al menos tan largo como el valor más largo que necesitemos.
  2. bucle a través de las filas y use partes de cada una de las dos cadenas anteriores.

La lógica es exactamente igual que la suya , excepto Tengo cosas grandes con las que uso parte de, mientras que lo construyes poco a poco. La parte importante es las declaraciones de Math.Abs ​​(...) son idénticas a la versión anterior .... Son el límite a los valores que construimos.

Aquí hay una manera de hacerlo:

  main2  

Eso es solo algo para que pienses en ...

 

You know, it's nice to see code that does what it says, and a nice simple task that still requires some head scratching.... but I'll assume you're a Java beginner.

Basics

Going through some of the basic stuff...

  • you have the cont variable declared as a static variable outside the method, but the only place it is used is inside the method. In this case, you should move the declaration inside the main method. Also, nothing changes that state, so the program just runs, and runs, which is OK (as a beginner).
  • you do not close the input Scanner. Again, this is probably because the program never completes, but there are nice ways in Java7 to make sure it happens neatly, and without much effort.
  • you should probably validate the user input. If the user enters negative integers, it's actually OK (the program does nothing). More concerning is if the user enters 2000000000. You should set an upper bound.
  • you call this shape a 'diamond' but it is actually a square. The width and height are the same number of characters. You only need one variable, lines or width, not both.
  • it is confusing that you have both line and lines variable. There is no need for lines if you use width instead, so get rid of it (also since the user prompt is "Width:").

OK, that's some relatively simple stuff. Messing your code around using the above suggestions I get:

public static void main (String[] args) {     boolean cont = true;      try (Scanner input = new Scanner(System.in)) {         while (cont) {             System.out.print("Width: ");             int width = input.nextInt();             System.out.println();              if (width > 100) {                 System.out.println("Width too wide, reducing to 100");                 width = 100;             }              for (int line = 0; line < width; line++) {                 for (int spaces = 0; spaces < Math.abs(line - (width / 2)); spaces++) {                     System.out.print(" ");                 }                 for (int marks = 0; marks < width - 2 * (Math.abs(line - (width / 2))); marks++) {                     System.out.print("x");                 }                        System.out.println();             }             System.out.println();         }     } } 

Algorithm

OK, now, some algorithmic things:

  • System.out.print(...) and the println variants, are actually really slow. Calling them from inside loops is a real problem for performance, and is a bad habit to learn. These methods lock the console output, and are not nice to other threads either. Where possible, you should always batch up the character printing in to a larger statement.
  • Sometimes, taking stuff away is easier than adding it .... (cryptic hint).

We can solve a lot of the complexity in your loops by doing a couple of tricks. Here's a suggestion:

  1. Build up two Strings, one of spaces and the other of 'x' characters. Each should be at least as long as the longest value we will need.
  2. loop through the rows and use parts of each of the two above strings.

The logic is the exact same as yours except I have big things I use a part of, whereas you build it up bit by bit. The important part is the Math.abs(...) statements are identical to the previous version.... they are the limit to the values we build.

Here's a way to do it:

public static void main (String[] args) {     boolean cont = true;      try (Scanner input = new Scanner(System.in)) {         while (cont) {             System.out.print("Width: ");             int width = input.nextInt();             System.out.println();              if (width > 100) {                 System.out.println("Width too wide, reducing to 100");                 width = 100;             }              char[] spaces = new char[width / 2];             char[] exes = new char[width];             Arrays.fill(spaces, ' '); // now an array of spaces             Arrays.fill(exes, 'x'); // now an array of 'x'              for (int line = 0; line < width; line++) {                 String pad = new String(spaces, 0, Math.abs(line - (width / 2)));                 String fill = new String(exes, 0, width - 2 * (Math.abs(line - (width / 2))));                 System.out.println(pad + fill);             }             System.out.println();         }     } } 

That's just something for you to think about.....

 
 
     
     
12
 
vote

Las personas han entrado en muchas cosas importantes sobre la sintaxis, la estructura del programa, etc., pero creo que podría hacer que sus bucles sean mucho más simples y más fáciles de entender:

  int halfheight = (width + 1) / 2; int spaces = halfheight; int exes = width - 2 * spaces;  for (int i = 0; i < halfheight; i++) {     spaces--;     exes += 2;      // You could use the approaches suggested by other folk here instead of inner loops     for (int s = 0; s < spaces; s++)         System.out.print(" ");     for (int x = 0; x < exes; x++)         System.out.print("X");     System.out.print(" "); }  for (int i = 0; i < halfheight - 1; i++) {     spaces++;     exes -= 2;      for (int s = 0; s < spaces; s++)         System.out.print(" ");     for (int x = 0; x < exes; x++)         System.out.print("X");     System.out.print(" "); }   

(Creo que esto maneja exactamente los anchos impares y pares exactamente iguales que los suyos, excepto que no emite una línea en blanco inicial en el caso de un ancho uniforme. Asumí que este era un artefacto en lugar de parte de la especificación. )

El único 'Matemáticas' que hago es en la inicialización, luego lo bucle por cantidades que están completamente claras sin ningún cálculo, y cambie el número de exex y espacios en cada iteración de una manera que sea completamente obvia. Puede parecer que los diversos cálculos con abs1 e INTEGER no son complejos, sin embargo, cuando está depurando o intentando modificar ligeramente su código, perderá tiempo de pensar a través de diferentes casos (positivo, negativo, impar, incluso, primero, primera iteración, última iteración), y probablemente se encontrará solo probando valores diferentes something , 99887766555443333 , 9988776655544334 etc, en lugar de Poder ver la interacción precisa de cada variable en los casos del borde.

Tenga en cuenta que tengo 6 para los bucles y el código es mucho más largo que las partes correspondientes de la suya o de cualquier otra persona. No está reduciendo estos lo que hace que el código sea claro. Es el hecho de que es fácil agarrar lo que cada uno hace sin referirse a (mucho) cosas fuera del bucle que ayuda al mantenedor. IMHO (y sé que algunos estarían en desacuerdo), la repetición utilizada con moderación y simétrica, ya que aquí es más elegante de lo que sería si lo hubiera hecho.

 

People have gone into lots of important things about syntax, program structure, etc. But I think that you could make your loops much simpler and easier to understand:

int halfheight = (width + 1) / 2; int spaces = halfheight; int exes = width - 2 * spaces;  for (int i = 0; i < halfheight; i++) {     spaces--;     exes += 2;      // You could use the approaches suggested by other folk here instead of inner loops     for (int s = 0; s < spaces; s++)         System.out.print(" ");     for (int x = 0; x < exes; x++)         System.out.print("X");     System.out.print("\n"); }  for (int i = 0; i < halfheight - 1; i++) {     spaces++;     exes -= 2;      for (int s = 0; s < spaces; s++)         System.out.print(" ");     for (int x = 0; x < exes; x++)         System.out.print("X");     System.out.print("\n"); } 

(I believe that this handles odd and even widths exactly the same as yours, except that it doesn't output an initial blank line in the case of even width. I assumed this was an artefact rather than part of the spec.)

The only 'math' I do is in the initialization, then I loop by amounts which are completely clear without any calculation, and change the number of exes and spaces in each iteration in a way that is completely obvious. It may seem that the various calculations with abs and integer division are not complex, however when you are debugging or trying to slightly modify your code, you will waste time on thinking through different cases (positive, negative, odd, even, first iteration, last iteration), and will probably find yourself just testing different values something, something + 1, something - 1 etc, rather than being able to see the precise interaction of each variable at the edge cases.

Note that I have 6 for loops and the code is much longer than the corresponding parts of yours or anyone else's. It's not reducing these that makes the code clear. It's the fact that it is easy to grasp what each does without referring to (much) stuff outside of the loop that helps the maintainer. IMHO (and I know some would disagree), repetition used sparingly and symmetrically as it is here is more elegant than it would be if I factored it out.

 
 
10
 
vote

Es mala práctica para poner todo su código en main() . Aquí, tiene el problema adicional que 9988777665544336 hace tres cosas: Solicite la entrada, imprima el diamante y el bucle. (Por cierto, no ofrece una manera libre de errores de salir del bucle infinito). La mezcla de estas tareas en una función lo haría imposible, por ejemplo, para reutilizar su rutina de impresión de diamantes de alguna otra manera (como hacer un Cadena vertical continua de varios diamantes).

@ SYB0RG Ofreció una forma de dividir la rutina de entrada de la rutina de impresión. Iría más allá y sugeriría que una interfaz orientada a objetos sería un buen hábito de construir en Java. Aquí hay una forma:

  private static int promptWidth(Scanner input) {     System.out.print("Width: ");     return input.hasNextInt() ? input.nextInt() : 0; }  public static void main(String[] args) {     Scanner input = new Scanner(System.in);     int width;     // Exit cleanly on EOF, or if anything other than a positive     // integer is entered.     while ((width = promptWidth(input)) > 0) {         System.out.println();         new Diamond(width).draw(System.out);         System.out.println();     }     input.close(); }   

En otras palabras, un 9988777665544338 sabe cómo dibujarse a System.out .

Aquí hay otro enfoque:

  abs0  

que se basa en abs1 'S 99887776655443312 , que tendría que implementar usando un 99887766655443313 .

 

It's bad practice to put all of your code into main(). Here, you have the additional problem that main() does three things: prompt for input, print the diamond, and loop. (By the way, you offer no error-free way to exit from the infinite loop.) Mixing these tasks into one function would make it impossible, for example, to reuse your diamond-printing routine in some other way (such as making a continuous vertical string of several diamonds).

@syb0rg offered one way to split the input routine from the printing routine. I would go further and suggest that an object-oriented interface would be a good habit to build in Java. Here's one way:

private static int promptWidth(Scanner input) {     System.out.print("Width: ");     return input.hasNextInt() ? input.nextInt() : 0; }  public static void main(String[] args) {     Scanner input = new Scanner(System.in);     int width;     // Exit cleanly on EOF, or if anything other than a positive     // integer is entered.     while ((width = promptWidth(input)) > 0) {         System.out.println();         new Diamond(width).draw(System.out);         System.out.println();     }     input.close(); } 

In other words, a Diamond knows how to draw itself to System.out.

Here's another approach:

public static void main(String[] args) {     Scanner input = new Scanner(System.in);     int width;     // Exit cleanly on EOF, or if anything other than a positive     // integer is entered.     while ((width = promptWidth(input)) > 0) {         int width = input.nextInt();         System.out.println();         System.out.println(new Diamond(width));         System.out.println();     }     input.close(); } 

That relies on Diamond's .toString() method, which you would have to implement using a StringBuilder.

 
 
10
 
vote

De hecho, puedes hacerlo en un bucle. Como no hablo Java, así que usaré la sintaxis C #.

  abs4  

traducido a Java para su conveniencia ...

  abs5  
 

You can indeed do it in one loop. As I don't speak Java, so I'll use C# syntax.

public static void Main() {     string valueString;     int width;     do     {         Console.Write("Width:");         valueString = Console.ReadLine();     } while (!int.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out width) && width > 0 && width <= 100);     int half = (int)((double)width/2+0.5);     string pattern = new string(' ',width)+new string('*',width);     for (int row = 1; row <= width; row++)     {          int spaces = width-Math.Abs(half - row);         Console.WriteLine(pattern.Substring(spaces, spaces));     } } 

Translated to Java for your convenience ....

public static void main (String[] args) {      try (Scanner scanner = new Scanner(System.in)) {         int width;         do         {             System.out.print("Width:");             width = scanner.nextInt();         } while (width < 0 || width > 100);          char[] blanks = new char[width];         char[] exes = new char[width];         Arrays.fill(blanks, ' ');         Arrays.fill(exes, 'x');         String pattern = new String(blanks) + new String(exes);          int half = (int)((double)width / 2 + 0.5);         for (int row = 1; row <= width; row++)         {             int spaces = width - Math.abs(half - row);             // Java substring has arguments (first, last), not (first, length).             System.out.println(pattern.substring(spaces, spaces + spaces));         }                          System.out.println();     } } 
 
 
   
   

Relacionados problema

12  Impresión similar a la consola del mensaje JavaScript  ( Console like printing of message javascript ) 
Estoy aprendiendo a Javascript y he hecho un pequeño script de modificación de documentos muy simple que imprime un mensaje como si fuera alguien escribiendo ...

2  Connect4 con AI  ( Connect4 with ai ) 
He hecho una aplicación connect 4 consola en C ++ y amaría algunos comentarios. En este proyecto he aprendido sobre la herencia y el uso de funciones virtuale...

7  Conductor VGA simple para un kernel de juguete  ( Simple vga driver for a toy kernel ) 
Aprendo sobre el desarrollo del sistema operativo y siga el tutorial huesos desnudos en Osdev. Y hice algunas tareas adicionales de la sección avanzada. M...

3  Programa de Console ATM  ( Atm console program ) 
Decidí escribir un programa de cajero automático en mi idioma de programación favorito, C #. Probado con algunos números y estoy seguro de que le dará una s...

15  Juego de blackjack basado en texto  ( Text based blackjack game ) 
Soy un nuevo programador (he estado haciendo Java durante aproximadamente 7 semanas) y soy del tipo que quiera conseguirlo directamente, así que me pregunto c...

4  Descarga un git repo sin .git carpeta  ( Download a git repo without git folder ) 
Viniendo de Python, JavaScript y PHP, me gustaría aprender a escribir Ruby en la forma en que se "supone". El código de Python bien escrito se llama "Pythonic...

13  "¡Hola Mundo!" Programa utilizando una clase para imprimir  ( Hello world program using a class for printing ) 
Eche un vistazo a mi programa y déjeme saber cómo puedo mejorarlo. /* " To Print A Line On The Display Screen" Date:5th January 2011 Programmer:F...

5  Colector de archivos M3U  ( M3u file collector ) 
Soy nuevo en Python y escribió este código para recopilar todos los archivos en un archivo M3U (Lista de reproducción) y copiándolos en un directorio. impo...

6  PRIGO DE PODER TICTACTOO EN C #  ( Command prompt tictactoe in c ) 
Escribí un juego básico de comando TIC TAC TOE juego. Quiero saber qué se puede mejorar en términos de modelado y qué errores he hecho (si corresponde). vo...

0  Herramienta de línea de comandos para extraer, buscar y convertir  ( Command line tool for extracting searching and converting ) 
Acabo de completar mi primera aplicación real (aplicación de línea de comandos). Es simple, pero no tenía conocimiento previo de Python. Todo fue golpeado y f...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos