Generator losowych hasel: rand() w petli

0

Witam,
Mam za zadanie napisać w c++ generator losowych haseł, taki że:

  • użytkownik ma podać długość hasła
  • hasło ma zawierać min. 1 wielką literę, 1 znak specjalny, 1 cyfrę
  • dwie spółgłoski/dwie samogłoski nie mogą ze sobą sąsiadować
    Oto dotychczasowy napisany kod:
/*
	Name: Generator losowego hasla
	Copyright: ---
	Author: Jan Dlugosz
	Date: 14/03/16 17:06
	Description: 
*/
#include<boost/algorithm/string/predicate.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <sstream>

char uv[] = "AEIOUY";
char uc[] = "BCDFGHJKLMNPQRSTVWXZ";
char nmbr[] = "1234567890";
char sgn[] = "`~!@#$%^&*()";
char lv[] = "aeiouy";
char lc[] = "bcdfghjklmnpqrstvwxz";
int n, i;

bool okz=false, okl=false, okd=false, ok=false;


std::stringstream sszkielet;

int rndtype() {									//losowy "typ" - wg kolejnosci deklarowania tablic - 1 odpowiada wielkiej samoglosce; 2 wielkiej spolglosce itd									
	return(std::rand() % 6 +1);
}

char rndlv() {									//m. samogloska
return(lv[std::rand() % std::strlen(lv)]);
}

char rnduv() {  								//w. samogloska
return(uv[std::rand() % std::strlen(uv)]);
}

char rndlc() {									//m. spolgloska
return(lc[std::rand() % std::strlen(lc)]);
}

char rnduc() {									//w. spolgloska
return(uc[std::rand() % std::strlen(uc)]);
}

char rndnmbr() {								//nr
return(nmbr[std::rand() % std::strlen(nmbr)]);
}

char rndsgn() {									//znak specjalny
return(sgn[std::rand() % std::strlen(sgn)]);
}




int main () {
srand(time(NULL));
	std::cout << "Witaj w generatorze hasel" << std::endl;
	
	std::cout << "Ile znakow ma byc w hasle?" << std::endl;
	std::cin >> n;
	
std::string szkielet;
	do {	
	
		sszkielet.str(std::string());
		okl = false, okz = false, okd = false, ok=false;

		for (i=0; i<n; i++){
			sszkielet << rndtype();
			std::cin.ignore();
		}
		
		sszkielet >> szkielet;
		
		if (szkielet.find('3') != std::string::npos){
 	   okl=true;
		}	
		if (szkielet.find('4') != std::string::npos){
	   	 okz=true;
		}
		if (szkielet.find('2') != std::string::npos){
   		 okd=true;
		}
		if (szkielet.find('1') != std::string::npos){
   		 okd=true;
		}
		if (okl==true && okz==true && okd==true){
			ok=true;
			break;
		}
	std::cout << szkielet <<std::endl<<okl<<okz<<okd<<ok;
	} while (1);
		std::cout << szkielet <<std::endl<<okl<<okz<<okd<<ok;
}
 

Moim pomysłem było aby gdy wygenerowany "szkielet"(string złożony z cyfr od 1-6, odpowiadającym kolejno 1:wlk. samogłosce; 2: wlk. spółgłosce; 3: cyfrze; 4:znakowi specjalnemu; 5:m. samogłosce; 6: wielkiej samogłosce) nie spełnia warunków zadania (okz, okd, okl w kodzie) generowany byl nowy "szkielet".
Jednak przy probie kolejnej iteracji, gdy wygenerowany został już jakiś nieprawidłowy "szkielet", liczby generowane nie zmieniaja sie.
Proszę o podpowiedz jak wybrnąć z tej sytuacji.
Pozdrawiam

0

Podejdź do tego inaczej,
wstawiasz: "665543" losujesz pozycje 0..3 i zmniejszasz ją o 4 czyli z 6 wyjdzie 2 zaś z 5 wyjdzie 1
Po czym uzupełniasz do potrzebne długości losowo.
Robisz shuffle() i już jedyne co musisz sprawdzić czy samogłoski są obok siebie.

1

napisz funkcję sprawdzającą czy wszystkie warunki są spełnione.
Najprostsze rozwiązanie losować dowolne hasło dopóki funkcja testująca nie stwierdzi, że hasło jest do przyjęcia.
Inne metody powinny być zakończone sprawdzeniem czy te warunki są spełnione, więc ta funkcja i tka ci się przyda (forma testu poprawności).

0

Taki właśnie był mój pierwszy pomysł, ale nie za bardzo wiem jak się zabrać do części takiej funkcji,
która sprawdzałaby ostatni z warunków tzn. sąsiedztwo dwóch samo/spółgłosek.

13thDragon, czy takie rozwiązanie nie zwracałoby przypadkiem jednej i tylko jednej wielkiej litery?
Wiem że najprawdopodobniej dla prowadzącego byłoby to jak najbardziej do zaakceptowania,
ale mimo wszystko chciałbym spróbować napisać coś, czego ograniczenie losowości wynikałoby tylko z
niedoskonałości rand();

Dodatkowo chciałbym spytać czy jest możliwość odwoływania się do danej pozycji w stringu,
tak jak przy char[]?

Dziękuję za wszystkie dotychczasowe odpowiedzi i pozdrawiam.

0

tak, można zrobić string[pozycja]

0

Witam,
Z kodem udało mi się uporać, pozwolę go sobie tutaj wrzucić jeżeli ktoś w przyszłości szukałby podobnego zagadnienia.
W sumie lepiej byłoby zastąpić goto w poniższym kodzie jakąś pętlą z break'iem, ale jest jak jest.
Pozdrawiam i dziękuję za wszystkie podpowiedzi

#include <iostream>
#include <sstream>
#include <cstring>
#include <ctime> 
#include <cstdlib>
#include <random>			 // Ta biblioteka wymaga kompilacji z dodatkowym argumentem -std=c++11

char uv[] = "AEIOUY";
char uc[] = "BCDFGHJKLMNPQRSTVWXZ";
char nmbr[] = "1234567890";
char sgn[] = "`~!@#$%^&*()";
char lv[] = "aeiouy";
char lc[] = "bcdfghjklmnpqrstvwxz";
char ctrl;
char rndlv() {                                    //m. samogloska
return(lv[rand() % std::strlen(lv)]);
}
 
char rnduv() {                                  //w. samogloska
return(uv[rand() % std::strlen(uv)]);
}
 
char rndlc() {                                    //m. spolgloska
return(lc[rand() % std::strlen(lc)]);
}
 
char rnduc() {                                    //w. spolgloska
return(uc[rand() % std::strlen(uc)]);

}
 
char rndnmbr() {                                //nr
return(nmbr[rand() % std::strlen(nmbr)]);
}
 
char rndsgn() {                                    //znak specjalny
return(sgn[rand() % std::strlen(sgn)]);
}



bool isok (std::string x) {  //funkcja sprawdzajace poprawnosc szkieletu
int a=x.size();
	int n=0;
		if (x.find('3') == std::string::npos){
      	  return(false);
        }    
        if (x.find('4') == std::string::npos){
           return(false);
        }
        if (x.find('2') == std::string::npos && x.find('1') == std::string::npos ){
           return(false);
        }

    for (int w=0; w <= a; ++w)
  	  if (x[w] == x[w-1] || x[w] +4 == x[w-1] || x[w] -4 == x[w-1]){
    		return (false);
		}
	
	return (true);
}

int main () {
	srand(time(NULL));
	std::mt19937 mt_rand(time(NULL));
	
	std::string szkielet, haslo;
	std::stringstream sszkielet, shaslo;
	
	int n;
	
	std::cout << "Witaj w generatorze hasel" << std::endl;
	start:
	std::cout << "Prosze podac liczbe znakow w hasle (minimum 3 znaki)" << std::endl; //Minimum 3 znaki, bo w mniejszej ilosci nie da sie spelnic wszystkich warunkow funkcji isok()
	std::cin >> n;
generuj:
	sszkielet.str("");
		for (int i=0; i<n; ++i) {
			sszkielet << mt_rand() % 6 +1;
		}
	
	 szkielet = sszkielet.str();
if (isok(szkielet)==false) goto generuj;
// W tym miejscu mam juz wygenerowany i sprawdzony poprawny szkielet
	for (int p=0; p<=n; p++) {
		switch (szkielet[p]) {
			case '1' :
			shaslo << rnduv();
				break;
				
			case '2' :
			shaslo << rnduc();
				break;
				
			case '3' :
			shaslo << rndnmbr();
				break;
				
			case '4' :
			shaslo << rndsgn();
				break;
				
			case '5' :
			shaslo << rndlv();
				break;
				
			case '6' :
			shaslo << rndlc();
				break;
		}
	}	
	haslo = shaslo.str();	
	shaslo.str("");
	std::cout << std::endl << "Wygenerowane haslo:  " << haslo << std::endl << "Czy chcesz generowac jeszcze raz?(y/n)" << std::endl;
	std::cin >> ctrl;
	if (ctrl == 'y' || ctrl == 'Y') goto start;
	
	
	return(0);
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1