3

Comunidad, les pido la ayuda con un pequeño problema. Estoy recién aprendiendo C++ y he estado trabajando con arreglos y matrices, entiendo la lógica de como imprimir una matriz y como recorre sus contenidos, pero hay cosas que aún no las puedo resolver. En el siguiente código se muestra como se imprime (con el valor 0) por terminal una matriz de AxA, siendo A un input recibido por teclado.

#include <iostream> 
using namespace std;

int main( ) {
  while( 1 ) {
    int a = 0;
    int i = 0;
    int j = 0;

    cout << "Ingresa dimensiones del cuadrado" << endl;
    cin >> a;

    if( cin.fail( ) ) {
      cout << "Input incorrecto" << endl;
      cin.clear( );
      cin.ignore( );
    } else {
      for( i = 1; i <= a; i++ ) {
        for( j = 1; j <= a; j++ ) {
          cout << " o ";
        }
        cout << endl;
      }
    }       
  }
}

Si el valor de A es 4, debería imprimir lo que aparece en la imagen-punto 1. Sin embargo, necesito solo imprimir los bordes, es decir si el valor de A es 4, el resultado debería ser el que se observa en la imagen-punto 2

introducir la descripción de la imagen aquí

Esta regla se debe cumplir para cualquier valor de a.

Muchas gracias

Trauma
  • 25,297
  • 4
  • 37
  • 60
E. Vargas
  • 33
  • 1
  • 5
  • No es lo mismo, pero seguro que te sirve: [Patrones de dibujo en C](http://es.stackoverflow.com/q/41354/19610) – Trauma Apr 05 '17 at 18:27
  • [Esta pregunta también habla de eso](http://es.stackoverflow.com/questions/59214/pintar-un-marco-en-c/59216#59216). Si usas windows, tambien se puede usar la librería win.h para manipular la consola – UselesssCat Apr 05 '17 at 18:37
  • @ArieCwHat esa pregunta que indicas es de `c#`. No creo que le sirva :-) – Trauma Apr 05 '17 at 18:59
  • bueno, el algoritmo básicamente es el mismo y si usa las librerías de windows como en la [documentación](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686974(v=vs.85).aspx).. igual le sirve :P – UselesssCat Apr 05 '17 at 19:01

3 Answers3

6

Lo que necesitas es que se imprima un elemento visible cuando las filas o las columnas tengan su valor máximo o mínimo, un elemento no visible en caso contrario.

Propuesta.

std::string si(" o "), no("   ");

for(i = 1; i <= a; i++ ) {
    for(j = 1; j <= a; j++ ) {
        cout << (i == 1 || j == 1 || i == a || j == a ? si : no);
    }
    cout << endl;
}

A tener en cuenta.

En general, no se aconseja usar using namespace std;, consulta esta pregunta para conocer el por qué.

Por otro lado, el uso de std::endl puede derivar en problemas de rendimiento porque vacía el búfer; aunque en un programa tan sencillo como el tuyo no supondrá ningún problema. Consulta esta pregunta para tener más detalles.

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
  • Muchas gracias por tu ayuda amigo, interesante lo que me comentas de using namespace std y lo de endl, lo tomaré en consideración. – E. Vargas Apr 06 '17 at 15:40
3

Dado que en C++ los índices empiezan en 0 deberías plantearte modificar tus bucles para que trabajen en el intervalo (0..a-1) en vez de (1..a). Es más natural y reduce las posibilidades de cometer errores al mezclar ambos rangos.

Bien, si suponemos que has modificado los bucles entonces los bordes se deben pintar en las siguientes condiciones:

  • i==0
  • i==a-1
  • j==0
  • j==a-1

Y el efecto podría conseguirse con algo tal que:

for( int i = 0; i < a; i++ ) {
  for( int j = 0; j < a; j++ ) {
    if( i==0 || i==a-1 || j==0 || j==a-1 )
      std::cout << " o";
    else
      std::cout << "  ";
  }
  std::cout << std::endl;
}

Las 4 comprobaciones podrián reducirse a dos si hacemos uso del resto:

for( int i = 0; i < a; i++ ) {
  for( int j = 0; j < a; j++ ) {
    if( i%(a-1) == 0 || j%(a-1)==0 )
      std::cout << " o";
    else
      std::cout << "  ";
  }
  std::cout << std::endl;
}

Incluso se podría mejorar un poquito más si a lo anterior se aplica lógica inversa:

for( int i = 0; i < a; i++ ) {
  for( int j = 0; j < a; j++ ) {
    if( i%(a-1) && j%(a-1) )
      std::cout << "  ";
    else
      std::cout << " o";
  }
  std::cout << std::endl;
}

Ahora bien, el if queda como un pegote. Se puede eliminar tranquilamente usando un pequeño array y de la libreria iomanip:

const char relleno[] = { 'o', ' ' };

// ...

std::cout << std::setfill(' ');
for( int i = 0; i < a; i++ ) {
  for( int j = 0; j < a; j++ ) {
    std::cout << std::setw(2) << relleno[i%(a-1) && j%(a-1)];
  }
  std::cout << std::endl;
}
eferion
  • 49,291
  • 5
  • 30
  • 72
1

Podrías probar agregando en el segundo for, una comprobación para saber si es un borde, o si es un valor en el centro del dibujo.

if (j = 1 || j = a)
    cout << " o ";
else
    cout << "   ";

A esto tendrias que agregarle que compruebe que no es la primer fila o la ultima, porque esas si van todas pintadas.

gbianchi
  • 19,675
  • 11
  • 38
  • 58