C++ Размещение случайных значений в диаграмме умножения (вложенный цикл)
Я создал таблицу умножения целых чисел 1...10. Вот код:
for (int i = 1; i <= 10; i++) {
for (int j = 1; j <= 10; j++) {
std::cout << "\t" << i * j;
}
std::cout << std::endl;
}
И мой вывод таков:
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
Проблема, с которой я борюсь, заключается в том, что мне нужно вставить случайное число, представляющее значение ошибки, в таблицу умножения. Например:
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 13 15 18 21 24 27 30
Как вы можете видеть в этом примере, значение ошибки равно 13, где 3 x 4 = 12, но вместо этого стоит число 13.
Я просмотрел бесчисленное количество сообщений на StackOverFlow и в Интернете.
Следует ли мне использовать другой цикл для вставки случайного числа? Если да, то как это сделать?
4 ответа
#include <iostream> // input/output
#include <random>
struct FieldData {
using Row = unsigned int;
using Col = unsigned int;
const Row rows{10};
const Col cols{10};
Row err_row;
Col err_col;
unsigned int err_value;
FieldData() {} // use default values for rows/cols
FieldData(Row max_row, Col max_col) : rows(std::move(max_row)), cols(std::move(max_col)) {} // use given values for rows/cols
};
void print_field(const FieldData& data)
{
for (FieldData::Row row=1;row <= data.rows; row++)
{
for (FieldData::Col col = 1; col <= data.cols; col++)
{
if (row == data.err_row && col == data.err_col)
std::cout << "\t" << data.err_value;
else
std::cout << "\t" << row*col;
}
std::cout << std::endl;
}
}
FieldData get_field(std::mt19937& generator)
{
FieldData data;
std::uniform_int_distribution<FieldData::Row> dist_rows(1, data.rows); // random for row
std::uniform_int_distribution<FieldData::Row> dist_cols(1, data.cols); // random for col
std::uniform_int_distribution<FieldData::Row> dist_result(1, data.rows*data.cols); // random for result
data.err_row = dist_rows(generator);
data.err_col = dist_cols(generator);
data.err_value = dist_result(generator);
if (data.err_value != data.err_row*data.err_col)
data.err_value--; // avoid correct value on error pos
return data;
}
int main()
{
std::random_device rd;
std::mt19937 generator(rd());
while (true)
{
auto field = get_field(generator);
print_field(field);
// some code to ask the user and so on.... (std::cin ...)
std::cout << "Error value '" << field.err_value << "' is on row " << field.err_row << ", col " << field.err_col << std::endl;
// if (... some code to check if user wants to break...)
break;
// code to go on
// go on
std::cout << std::endl;
}
}
По просьбе автора, версия без дополнительных конструкций:
#include <iostream> // input/output
#include <random>
int main()
{
std::random_device rd;
std::mt19937 generator(rd());
unsigned int rows = 10;
unsigned int cols = 10;
std::uniform_int_distribution<unsigned int> dist_rows(1, rows); // random for row (1 to value of field_rows)
std::uniform_int_distribution<unsigned int> dist_cols(1, cols); // random for col (1 to value of field_cols)
std::uniform_int_distribution<unsigned int> dist_result(1, rows * cols); // random for result
while (true) // infinite loop - must be interrupted explicitly with break or similar
{
unsigned int err_row = dist_rows(generator); // Generate the random number that defines the row
unsigned int err_col = dist_cols(generator); // Generate the random number that defines the col
unsigned int err_value = dist_result(generator); // Generate the random value
if (err_value != err_row * err_col)
err_value--; // avoid correct value on error position - simple decrement the value
// print_field
for (unsigned int row = 1; row <= rows; row++)
{
for (unsigned int col = 1; col <= cols; col++)
{
if (row == err_row && col == err_col) // condition to insert the error value
std::cout << "\t" << err_value;
else
std::cout << "\t" << row * col;
}
std::cout << std::endl;
}
//
// some code to ask the user and so on.... (std::cin ...)
//
std::cout << "Error value '" << err_value << "' is on row " << err_row << ", col " << err_col << std::endl;
// if (... some code to check if user wants to break...)
break;
// code to go on
// go on
std::cout << std::endl;
}
}
Надеюсь, этот ответ поможет вам, я немного разделил разные части, чтобы сделать его более понятным для вас. Код должен хотя бы дать вам общее представление о том, как можно реализовать нечто подобное. В зависимости от варианта использования, конечно, будет уместен отдельный класс или что-то подобное. Код во втором варианте отличается от функциональности только тем, что uniform_int_distributions находятся за пределами области while(true) и, таким образом, не всегда "перестраиваются", как в случае первого варианта (поскольку более динамичный и модульный подход был бы возможен в принцип).
Вы можете использовать <random>
заголовочный файл для этого.
std::random_device rd;
std::mt19937 gen(rd());
// it produces uniformly distributed random integers in the range [a, b] (both inclusive)
std::uniform_int_distribution<> dis(0, 1); // either add 0 or 1 (1 will be the error -- can change a,b according to your need)
for (int i = 1; i <= 10; i++)
{
for (int j = 1; j <= 10; j++)
{
std::cout << "\t" << i * j + dis(gen); // just add the error value to your multiplication
}
std::cout << std::endl;
}
Следует ли использовать другой цикл для вставки случайного числа? Если да, то как это сделать?
Вы вставляете только одну ошибку, поэтому цикл для этого не имеет особого смысла.
Хорошо, а почему бы вам сначала не решить, куда идет случайное число? Как только вы это узнаете, вы можете изменить тело внутреннего цикла следующим образом:
int value = i * j;
if ((i == error_location.row) and (j = error_location.column)) {
value = // code for introducing an error, e.g. sample a random answer,
// or a random offset added to the correct answer etc.
}
std::cout << "\t" << i * j;
Решение о позиции для ошибочных значений может быть принято с использованием заголовка C++, как объясняется в этом вопросе. В вашем случае это будет примерно так:
constexpr const int table_leg { 10 };
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> coordinate_distribution(0, table_leg - 1);
struct { int row, col; } error_location =
{ coordinate_distribution(gen), coordinate_distribution(gen) };
Примечания:
- Предлагаю заменить
i
с участиемrow
илиrow_index
а такжеj
с участиемcol
илиcolumn
илиcolumn_index
; также, используя именованную константу вместо повторения "магического числа"10
. - Я предположил, что вы не хотите хранить свою таблицу умножения в буфере, а затем заменить одно значение там ошибкой. Если будут хранить таблицы где - то, вы могли бы избежать сложного внутреннего цикла и просто установить ошибку после заполнения всех правильных значений.
Так что спасибо всем, особенно @Wolfgang. Я прочитал случайный заголовочный файл C++11 и его функции. Я создал исходный код со случайными функциями и без них. Мы будем признательны за любой канал о том, как сделать мой исходный код более эффективным. Помимо этого, он достигает того, что мне нужно.
#include <iostream>
#include <ctime>
#include <iomanip>
const unsigned int ROWS = 10;
const unsigned int COLUMNS = 10;
void randomValue(unsigned int &, unsigned int &, unsigned int &);
int main()
{
unsigned int rValue;
unsigned int cValue;
unsigned int pValue;
unsigned int rowError;
unsigned int columnError;
unsigned int productError;
unsigned int userRowGuess;
unsigned int userColumnGuess;
char choice;
do
{
randomValue(rValue, cValue, pValue);
std::cout << "\033[2J\033[0;0H"; // This code clears the screen
std::cout << std::endl << std::endl;
std::cout << std::setw(35) << "++++++++++++++++++++++++" << std::endl;
std::cout << std::setw(35) << "+ Multiplication Table +" << std::endl;
std::cout << std::setw(35) << "++++++++++++++++++++++++" << std::endl;
std::cout << std::endl << std::endl;
while (true)
{
rowError = rValue;
columnError = cValue;
productError = pValue;
if (productError == rowError * columnError)
{
productError--;
}
for (unsigned int row = 1; row <= ROWS; row++)
{
for (unsigned int column = 1; column <= COLUMNS; column++)
{
if (row == rowError && column == columnError)
{
std::cout << "\t" << "" << productError;
}
else
{
std::cout << "\t" << row * column;
}
}
std::cout << std::endl;
}
break;
}
std::cout << std::endl << std::endl;
std::cout << "\t\t" << "Type in the column number " << std::endl;
std::cout << "\t\t" << "of the location of the " << std::endl;
std::cout << "\t\t" << "error & then press " << std::endl;
std::cout << "\t\t" << "[Enter]: ";
std::cin >> userColumnGuess;
std::cout << std::endl;
std::cout << "\t\t" << "Type in the row number " << std::endl;
std::cout << "\t\t" << "of the location of the " << std::endl;
std::cout << "\t\t" << "error & then press " << std::endl;
std::cout << "\t\t" << "[Enter]: ";
std::cin >> userRowGuess;
std::cout << std::endl;
if (userRowGuess != rowError && userColumnGuess != columnError)
{
std::cout << "\t\t" << "Your answer was incorrect!" << std::endl << std::endl;
std::cout << "\t\t" << "Error value '" << productError << "' is located" << std::endl;
std::cout << "\t\t" << "on row " << rowError << ", column " << columnError << "." << std::endl;
}
else
{
std::cout << "\t\t" << "You are correct! You win!" << std::endl;
}
std::cout << std::endl;
std::cout << "\t\t" << "Would you like to play again?" << std::endl << std::endl;
std::cout << "\t\t" << "Type in 'Y' for yes or 'N'" << std::endl;
std::cout << "\t\t" << "for no & then press [Enter]: ";
std::cin >> choice;
while (choice != 'y' && choice != 'Y' && choice != 'n' && choice != 'N')
{
std::cout << std::endl;
std::cout << "\t\t" << "Invalid entry. Only 'Y' or 'N'" << std::endl;
std::cout << "\t\t" << "are accepted answers." << std::endl << std::endl;
std::cout << "\t\t" << "Would you like to play again?" << std::endl << std::endl;
std::cout << "\t\t" << "Type in 'Y' for yes or 'N' for" << std::endl;
std::cout << "\t\t" << "no & then press [Enter]: ";
std::cin >> choice;
}
std::cout << std::endl;
} while (choice == 'y' || choice == 'Y');
std::cout << "\t\t" << "Press [Enter] to continue....." << std::endl;
std::cin.get();
std::cin.get();
return 0;
}
void randomValue(unsigned int &rValue, unsigned int &cValue, unsigned int &pValue)
{
srand((unsigned)time(NULL));
unsigned int r = rValue = (rand() % ROWS) + 1;
unsigned int c = cValue = (rand() % COLUMNS) + 1;
unsigned int p = pValue = (rand() % (ROWS * COLUMNS)) + 1;
}