Reputation: 2542
I am not sure if anyone is familiar with the monster rancher games but I would like to implement a system like their's.
The way it works is they use an outside source to obtain a seed for a RNG and then create a monster and it stats based on the results. They use a CD, a new ds game use sounds.
I was wondering how would I obtain a seed from an outside medial such a a cd in a programming sense. As far as i see a seed is just a number so using C++ how can I get numbers from things attached to my computer? I was thinking I could use what is plugged into the USB port, would be kind of interesting?
EDIT: I am not looking at how to get a random seed, I want to know how I can read a CD of something like that to produce a number I can uses as a seed. The CD would always produce the same seed value and different CD's would produce different seed values.
Upvotes: 3
Views: 196
Reputation: 103693
Yes, I remember that game. Simple solution. Get a list of files on the drive using something like boost.filesystem.
Then decide on some scheme to generate the seed based on those files. It could be something as simple as taking the first file in alphabetical order, then reading the file in binary and just taking the first four bytes as an 32 bit word. But that will probably not generate values quite as unique as you would like. Better would probably be to do some kind of hash involving several files.
Here's a simple example. It finds the first file on the K drive that has a size greater than sizeof(unsigned int)
, retrieves that many bytes from it, and stores it in a value. Obviously that's not very sophisticated, but it should get you started.
#include <iostream>
#include <fstream>
#include <boost/filesystem.hpp>
int main()
{
namespace fs = boost::filesystem;
unsigned int seed = 0;
fs::recursive_directory_iterator begin("K:/"), end;
while (begin != end)
{
if (fs::is_regular_file(*begin)
&& fs::file_size(*begin) >= sizeof(seed))
{
std::ifstream fin(begin->path().string(), std::ios::binary);
fin.read((char*)&seed, sizeof(seed));
break;
}
++begin;
}
std::cout << "Seed = " << seed << '\n';
}
Upvotes: 3
Reputation: 8310
std::string tohash;
std::cin >> tohash;
boost::hash<std::string> string_hash;
std::size_t theRandomNumber = string_hash(tohash);
Replace std::cin with a file name read from the cd or file system, the contents of a file, whatever.
Upvotes: 0
Reputation: 392911
On unix, just
dd if=/dev/sr0 bs=512 count=32
or open /dev/sr0 in binary mode from code. On Windows, see this snippet (from this page). It supports Win98/2k etc. The sample uses A:, but you can also specify
a physical drive for raw reading as "\\\\.\\PhysicalDrive0"
or "\\\\.\\PhysicalDrive1"
... etc
// All msdos data structures must be packed on a 1 byte boundary
#pragma pack (1)
struct
{
DWORD StartingSector ;
WORD NumberOfSectors ;
DWORD pBuffer;
}ControlBlock;
#pragma pack ()
#pragma pack (1)
typedef struct _DIOC_REGISTERS
{
DWORD reg_EBX;
DWORD reg_EDX;
DWORD reg_ECX;
DWORD reg_EAX;
DWORD reg_EDI;
DWORD reg_ESI;
DWORD reg_Flags;
} DIOC_REGISTERS ;
#pragma pack ()
char * ReadSectors(int drive, DWORD startinglogicalsector, int numberofsectors)
{
char* buffer = (char*)malloc (512*numberofsectors);
HANDLE hDevice ;
DIOC_REGISTERS reg ;
BOOL fResult ;
DWORD cb ;
// Creating handle to vwin32.vxd (win 9x)
hDevice = CreateFile ( "\\\\.\\vwin32",
0,
0,
NULL,
0,
FILE_FLAG_DELETE_ON_CLOSE,
NULL );
if ( hDevice == INVALID_HANDLE_VALUE )
{
// win NT/2K/XP code
HANDLE hDevice;
DWORD bytesread;
char _devicename[] = "\\\\.\\A:";
_devicename[4] += drive;
// Creating a handle to disk drive using CreateFile () function ..
hDevice = CreateFile(_devicename,
GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
return NULL;
// Setting the pointer to point to the start of the sector we want to read ..
SetFilePointer (hDevice, (startinglogicalsector*512), NULL, FILE_BEGIN);
if (!ReadFile (hDevice, buffer, 512*numberofsectors, &bytesread, NULL) )
return NULL;
}
else
{
// code for win 95/98
ControlBlock.StartingSector = (DWORD)startinglogicalsector;
ControlBlock.NumberOfSectors = (DWORD)numberofsectors ;
ControlBlock.pBuffer = (DWORD)buffer ;
//-----------------------------------------------------------
// SI contains read/write mode flags
// SI=0h for read and SI=1h for write
// CX must be equal to ffffh for
// int 21h's 7305h extention
// DS:BX -> base addr of the
// control block structure
// DL must contain the drive number
// (01h=A:, 02h=B: etc)
//-----------------------------------------------------------
reg.reg_ESI = 0x00 ;
reg.reg_ECX = -1 ;
reg.reg_EBX = (DWORD)(&ControlBlock);
reg.reg_EDX = drive+1;
reg.reg_EAX = 0x7305 ;
// 6 == VWIN32_DIOC_DOS_DRIVEINFO
fResult = DeviceIoControl ( hDevice,
6,
&(reg),
sizeof (reg),
&(reg),
sizeof (reg),
&cb,
0);
if (!fResult || (reg.reg_Flags & 0x0001)) return NULL;
}
CloseHandle(hDevice);
return buffer;
}
Upvotes: 0
Reputation: 71525
There is no portable way. On most Unix systems, you can read /dev/random
or /dev/urandom
.
On Windows, try CryptGenRandom
.
(For this sort of application, cryptographically strong pseudo-random numbers are just as good as "true" random numbers. Prove me wrong and you can get a Ph.D. from any university in the world.)
[edit]
Sorry, I thought you were looking for a decent way to roll a random character. If you are trying to use the same number every time, just store the seed in a file and use any old pseudo-random number generator.
Upvotes: 0