你站在地牢里。在你之前,有一组5级书呆子。他们希望你为他们开展“龙与地下城”活动。
你开了几场比赛,你的球员正在升级,而且事情通常会膨胀。但是战斗有点慢。你决定拿出你的+4 Halberd of Objective-C并编写一个iPad应用来自动化NPC骰子在战斗中滚动。 威胁说,书呆子向你走来。 “算法生成的数字,”一个人咆哮道,“是对真正随机性的空洞模仿!你不应该用你的伪随机污秽来玷污我们的圣战!”
你滚动说服他arc4random_uniform()
不仅仅是足够......而且失败了。书呆子会满足于真正的随机性。当你拼命地依赖你的MacBook时,他们会把你当作囚犯,写一个从random.org中检索数据的课程。
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"YYYY/YYYY-MM-dd"];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@%@",
@"http://www.random.org/files/",
[formatter stringFromDate:[NSDate date]],
@".bin"]];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:
[NSURLRequest requestWithURL:url] delegate:self];
保存数据后,您可以从下载的字节中生成随机数0-255。
-(int) nextInt:(int)start end:(int)end
{
int upperBound = end - start + 1;
unsigned char result;
int maxModulo = 255 - (255 % upperBound);
do {
NSRange range = {index, sizeof(char)};
[randos getBytes:&result range:range];
index += sizeof(char);
} while (result > maxModulo); //avoid modulo bias
result = result % upperBound;
result += start;
return result;
}
书呆子似乎很满意,但是出现了一个新的敌人:另一个地牢大师!他要求你出于自己的目的给他一份软件副本。问题很明显 - 如果你们都在同一天使用random.org数据,你将获得相同的骰子卷!
所以我的问题如下:我如何修改random.org数据,使其保留类似“真正随机性”的内容,但在程序的每个实例中都有所不同?我可以想象一个解决方案,需要从用户like TrueCrypt does获得一些(据称是随机的)触摸板动作,但是一旦我有这个常数,我不确定从那里去哪里。以某种方式使用我的常量哈希所有数字?这将产生更大的数字;我在统计上是好的,如果我只是截断或模数到骰子卷?我不知道采取什么算法步骤。
答案 0 :(得分:5)
我有一个不同的解决方案。一个能满足每个人的,我希望。每次要生成新的掷骰子时,都要这样做:
显示进度条,并提示用户摇动设备。
当进度条一直向右移动时,播放掷骰子的声音并使用散列函数的输出(256位)生成骰子值。这不会超过59d20。您还可以将哈希函数状态保存为下一个掷骰子的输入。
这就是你告诉那些书呆子的事情:模具卷绝不是算法上可预测的。确定模具卷的唯一信息是你如何摇动设备,这对于真正的骰子也是如此。在理论中你可以用同样的方式摇动设备两次,就像在理论中一个高技能的赌徒可以掷出真正的骰子,让它们以他想要的方式出现。
如何使用输出:你有256位的随机数据,并希望得到掷骰。
struct bits {
unsigned data[8];
unsigned pos;
};
// Get next n bits, or -1 if out of entropy.
int get_bits(struct bits *b, int n);
// Roll an n-sided die, or -1 if out of entropy
int uniform(struct bits *b, int n)
{
int nbits, x;
for (nbits = 0; (1 << nbits) < n; ++nbits);
do {
x = get_bits(b, nbits);
if (x < 0)
return -1;
} while (x >= n);
return x + 1;
}
此功能的工作原理是一次切割几个熵的骰子。因此对于d8,您需要切3位并使用结果。对于d20,你为d32切掉5位,如果结果大于20则重新滚动。如果你碰巧用完给定的掷骰子的熵(不太可能,但可能),那么我建议打印一个“骰子”高举“消息并要求用户为剩下的骰子摇一摇。
脚注:除非你滚动大量的骰子,否则你的熵耗尽的概率非常低。 256位就足够了。在熵耗尽之前需要24d20甚至达到1%。
答案 1 :(得分:4)
这不是一个真正的答案而且是一个评论,但它变得很长而且就在这里。
我可以想象一个解决方案,需要从用户那里获得一些(据称是随机的)触摸板动作,
请注意,arc4random_stir()
从/dev/urandom
读取,请参阅the man page。所以它以“环境”为自己种子。
或者,购买放射源和盖革计数器,将其连接到USB,并根据计数器的读数生成随机数。核衰变是量子力学随机的。
答案 2 :(得分:2)
生成加密安全随机字节数组。
int SecRandomCopyBytes (
SecRandomRef rnd,
size_t count,
uint8_t *bytes
);
Apple Randomization Services Reference Docs
或者只是使用arc4random(),它尽可能接近随机,它会自动从/ dev / urandom播种。
答案 3 :(得分:1)
下载bin-files.txt并随机选择其中一个条目(例如,使用NSDate timeIntervalSinceNow modulo txt文件中的条目数)。然后下载该文件。
此外,下载文件后,根据不同的随机数发生器开始一些偏移。
答案 4 :(得分:0)
无论使用哪种随机方法(我选择了_arc4random_uniform_),在某些时候仍然需要骰子计算器。
从方法主体中推断出标题。这是我的用途:
objective-c
//
// Dice.m
// TheeEndThee
//
// Created by Martin-Gilles Lavoie on 2019-10-19.
// Copyright © 2019 DoRyu. All rights reserved.
//
#import "Dice.h"
@implementation Dice
+ (NSInteger) roll: (NSUInteger) sides
times: (NSUInteger) numDices
plus: (NSInteger) bonus
{
NSInteger result = bonus;
while (numDices-- > 0)
{
result += (arc4random() % sides) + 1;
}
return result;
}
+ (NSInteger) roll100 { return [self roll: 100 times: 1 plus: 0]; }
+ (NSInteger) roll30 { return [self roll: 30 times: 1 plus: 0]; }
+ (NSInteger) roll24 { return [self roll: 24 times: 1 plus: 0]; }
+ (NSInteger) roll20 { return [self roll: 20 times: 1 plus: 0]; }
+ (NSInteger) roll12 { return [self roll: 12 times: 1 plus: 0]; }
+ (NSInteger) roll10 { return [self roll: 10 times: 1 plus: 0]; }
+ (NSInteger) roll8 { return [self roll: 8 times: 1 plus: 0]; }
+ (NSInteger) roll6 { return [self roll: 6 times: 1 plus: 0]; }
+ (NSInteger) roll4 { return [self roll: 4 times: 1 plus: 0]; }
+ (NSInteger) roll2 { return [self roll: 2 times: 1 plus: 0]; }
+ (NSInteger) rollStat { return [self roll: 6 times: 3 plus: 0]; }
+ (NSObject*) compute: (NSObject*) value
{
NSObject* result = value;
if ([value isKindOfClass: NSString.class])
{
NSString* expression = (id) value;
//whitespaces and newlines are nod valid dice expressions
if ([expression rangeOfCharacterFromSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]].location == NSNotFound
&& [expression hasPrefix: @"="])
{
expression = [expression substringFromIndex: 1];
NSInteger multiplier = 1;
NSInteger addition = 0;
NSInteger faces;
NSArray<NSString*>* components = [expression componentsSeparatedByString: @"+"];
if (components.count == 2)
{
addition = components.lastObject.integerValue;
expression = components.firstObject;
}
expression = expression.lowercaseString;
components = [expression componentsSeparatedByString: @"d"];
if (components.count == 2)
{
multiplier = components.firstObject.integerValue;
expression = components.lastObject;
}
faces = expression.integerValue;
if (faces > 0 && multiplier > 0)
{
result = @([self roll: faces
times: multiplier
plus: addition]);
#if DEBUG
NSLog(@"Dice \"%@\" = %@d%@+%@ = %@",
value, @(multiplier), @(faces), @(addition), result);
#endif
}
else
{
result = nil;
}
}
}
return result;
}
@end
[骰子计算:表达式] 将解析以下性质的表达式:
=6. // expression to roll a 6-sided dice
=1d6 // expression to roll a 6-sided dice
=6+2 // expression to roll a 6-sided dice and add 2
=1d6+2 // expression to roll a 6-sided dice and add 2
{multiplier} {d} faces {+ bonus}语法可以产生给定面孔的任何编号的骰子,最后带有奖励。
我的程序使用变量替换操作来处理“ 1d20 + MOD”之类的问题。在自己的程序中发疯。