2

Estoy aprendiendo C++. Estaba haciendo unos experimentos, entre ellos un programa donde hay 2 variables con valor de 100 y aletaroriamente se le resta un número a esas variables:

#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int main(){
    int vida = 100, evida = 100, rnd, rnd2;
    srand(time(NULL));  
    while(vida >= 0 || evida >= 0){
        rnd = 1+rand()%(11-1);
        cout<<vida<<"  "<<evida<<endl;
        rnd2 = 1+rand()%(3-1);
        if(rnd2 == 2){
            evida -= rnd;
        }
        else{
            vida -= rnd;
        }
    }
        return 0;
    }

La idea es que cuando la variable vida o evida lleguen a 0 se pare el while, pero en lugar de eso espera a que las 2 variables sean menores o iguales a 0. ¿Qué puedo hacer?

OscarGarcia
  • 26,999
  • 3
  • 26
  • 61
binario_newbie
  • 449
  • 4
  • 14

3 Answers3

4

Tú quieres que cuando al menos vida o evida sean menores o iguales a cero salga del while, es decir:

vida <= 0 OR evida <= 0

Esa es la condición para que salga por lo que la condición para que se mantenga es la negación:

~(vida <= 0 OR evida <= 0)     =
~(vida <= 0) AND ~(evida <= 0) =
  vida > 0 AND evida > 0

Por lo que la condición correcta es:

vida > 0 && evida > 0

Código:

#include <iostream>
#include <random>

int main(){
    int vida = 100, evida = 100, rnd, rnd2;
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<int> dis1(1, 11);
    std::uniform_int_distribution<int> dis2(1, 3);

    std::cout<<vida<<"  "<<evida<< "\n";
    while(vida > 0 && evida > 0){
        rnd = dis1(gen);
        rnd2 = dis2(gen);
        if(rnd2 == 2)
            evida -= rnd;
        else
            vida -= rnd;
        std::cout<<vida<<"  "<<evida<< "\n";
    }
    return 0;
}

Salida:

100  100
89  100
88  100
88  92
88  87
79  87
79  80
79  75
79  70
70  70
60  70
50  70
41  70
40  70
40  61
39  61
39  53
39  47
37  47
28  47
19  47
19  42
19  36
14  36
14  25
14  21
14  17
14  7
9  7
8  7
-1  7
  • 1
    Mi +1 por el uso de `std::uniform_int_distribution` :) aunque te aconsejo dejar un espacio en blanco entre la definición de tipo y el nombre de la instancia para facilitar la lectura y comprensión de la composición: `std::uniform_int_distribution dis2(1, 3);` – OscarGarcia Sep 14 '18 at 05:34
4

Estoy aprendiendo C++.

En ese caso, permíteme darte la bienvenida \ñ_ñ/ y darte algunos consejos:

  • Las cabeceras <stdlib.h> y <time.h> son de no de . Estas cabeceras disponen de una versión adaptada a C++ que tiene el prefijo c y carece de extensión. Si realmente necesitas usar las cabeceras de C (que nunca será el caso) debes usar los equivalentes de C++ <cstdlib> y <ctime> . Lee este hilo para saber por qué.
  • No hay obligación de usar la cláusula using namespace std; pues es sólo es una ayuda a la escritura de código; si decides usar esta cláusula no lo hagas en el ámbito global, úsala en el ámbito más pequeño posible. Lee este hilo para saber por qué.
  • Las funciones rand() y srand() pertenecen a las librerías de C, se desaconseja usar esas utilidades den C++ pues pueden no ser portables y pueden ofrecer resultados y rendimiento cuestionables, por ello se está estudiando deprecarlo . A partir del estándar C++11 existe una completa librería de generación de números pseudoaleatorios que deberías usar en su lugar. Lee este hilo para saber por qué.

La idea es que cuando la variable vida o evida lleguen a 0 se pare el while, pero en lugar de eso espera a que las 2 variables sean menores o iguales a 0.

Ese es el comportamiento esperado; en una condición unida por un or (||) la expresión será verdadera mientras alguna de las expresiones sea verdadera y en consecuencia será falsa cuando ambas expresiones lo sean:

|            tabla de la verdad OR           |
+-------------+-------------+----+-----------+
| expresión 1 | expresión 2 | || | resultado |
+-------------+-------------+----+-----------+
|    falso    |    falso    | || |   falso   |
|    falso    |  verdadero  | || | verdadero |
|  verdadero  |    falso    | || | verdadero |
|  verdadero  |  verdadero  | || | verdadero |

Tú lo que quieres es una condición and (&&), que será verdadera cuando todas las expresiones sea verdaderas y en consecuencia será falsa en los demás casos:

|           tabla de la verdad AND           |
+-------------+-------------+----+-----------+
| expresión 1 | expresión 2 | && | resultado |
+-------------+-------------+----+-----------+
|    falso    |    falso    | && |   falso   |
|    falso    |  verdadero  | && |   falso   |
|  verdadero  |    falso    | && |   falso   |
|  verdadero  |  verdadero  | && | verdadero |

Por lo tanto tu while, con and (&&):

while(vida >= 0 && evida >= 0)

Se podría leer como "Mientras vida sea mayor o igual a 0 Y evida sea mayor o igual a 0".

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
0

Tienes dos opciones, o poner un operador lógico Y (&&) en vez del O (||) y un mayor estricto (>):

#include <iostream>
#include <stdlib.h>
#include <time.h>

int main() {
    int vida = 100, evida = 100, rnd, rnd2;
    srand(time(NULL));
    while (vida > 0 && evida > 0) {
        rnd = 1 + rand() % (11 - 1);
        std::cout << vida << "  " << evida << std::endl;
        rnd2 = 1 + rand() % (3 - 1);
        if (rnd2 == 2) {
            evida -= rnd;
        } else {
            vida -= rnd;
        }
    }
    return 0;
}

O cambiar el mayor o igual (>=) por un menor o igual (<=) todo negado (!):

#include <iostream>
#include <stdlib.h>
#include <time.h>

int main() {
    int vida = 100, evida = 100, rnd, rnd2;
    srand(time(NULL));
    while (!(vida <= 0 || evida <= 0)) {
        rnd = 1 + rand() % (11 - 1);
        std::cout << vida << "  " << evida << std::endl;
        rnd2 = 1 + rand() % (3 - 1);
        if (rnd2 == 2) {
            evida -= rnd;
        } else {
            vida -= rnd;
        }
    }
    return 0;
}
OscarGarcia
  • 26,999
  • 3
  • 26
  • 61