Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
if ($diff > 0)
$dices[$j] = rand($diff, 6);
function splitDices($number, $dicesCount)
{
$x = rand(1, $number);
$x = rand(1, $dicesCount);
return splitDices($x, $y) + splitDices($number-$x, $dicesCount-$y);
}
function PermutationMaster(sum, dices) {
this.sum = sum;
this.dices = dices;
this.permutations = [];
this.run();
}
PermutationMaster.prototype = {
run: function(permutation, dice) {
permutation = permutation || [];
dice = dice || 1;
for (var j = 6; j; j--) {
permutation[dice - 1] = j;
if (dice < this.dices)
this.run(permutation, dice + 1);
else if (permutation.reduce(function(a, b) { return a + b; }) == this.sum)
this.permutations.push([].slice.apply(permutation));
}
},
random: function() {
return this.permutations[~~(Math.random() * this.permutations.length)];
}
}
var master = new PermutationMaster(18, 4);
console.log(master.random());
console.log(master.random());
console.log(master.random());
public static List<int> SplitDices(int number, int dicesCount)
{
if (dicesCount == 1)
return new List<int> { number };
var otherDices = dicesCount - 1;
var min = Math.Max(1, number - 6*otherDices);
var max = Math.Min(6, number - 1*otherDices);
var dice = random.Next(max - min) + min;
var other = SplitDices(number - dice, dicesCount - 1);
other.Add(dice);
return other;
}MAX_DICE_VAL = 6
def dices_for_num num, num_of_dices
raise 'Too many dices' if num < num_of_dices
raise 'Not enough dices' if num > num_of_dices * MAX_DICE_VAL
dices = []
dices_sum = 0;
num_of_dices.times do
dice_val = rand(1..MAX_DICE_VAL)
dices << dice_val
dices_sum += dice_val
end
delta = num - dices_sum
while delta != 0 do
dices.each_with_index do |val, index|
if delta > 0 and val < MAX_DICE_VAL
dices[index] += 1
delta -= 1
elsif delta < 0 and val > 1
dices[index] -= 1
delta += 1
end
end
end
dices
end
puts dices_for_num(16,4).inspect
MIN_DICE_VAL = 1
MAX_DICE_VAL = 6
def dices_for_num num, num_of_dices
raise 'Too many dices' if num < num_of_dices * MIN_DICE_VAL
raise 'Not enough dices' if num > num_of_dices * MAX_DICE_VAL
dices = []
for i in (0...num_of_dices).reverse do
lower_bound = [MIN_DICE_VAL, num - i * MAX_DICE_VAL].max
upper_bound = [num - i * MIN_DICE_VAL, MAX_DICE_VAL].min
dice_val = rand(lower_bound .. upper_bound)
dices << dice_val
num -= dice_val
end
dices
end
use_module(library(clpfd)).
N = 18,
sum([A, B, C, D], #=, N),
[A, B, C, D] ins 1..6,
findall([A, B, C, D], label([A, B, C, D]), List),
random_member(RandomResponse, List).
sum([A, B, C, D], #=, N)[A, B, C, D] ins 1..6findall([A, B, C, D], label([A, B, C, D]), List)random_member(RandomResponse, List)sum([A, B, C, D], #=, N), — бесконечное множество возможных решений, то есть уже на этой стадии программа зависнет. Точнее, не на этой стадии, а из-за этой стадии. Или, если предикат sum сделан по уму, вернет ошибку.[A, B, C, D] ins 1..6, чем-то классический Пролог напоминает. Действительно, сложностей в переборе 64 вариантов и присвоении их 4м переменным нет. Если такую строчку поменять с предыдущей, то это даже будет работать — sum сработает как фильтр.findall([A, B, C, D], label([A, B, C, D]), List) все 4 переменные, A, B, C и D — уже имеют свои фиксированные значения. Иными словами, вместо одного вызова findall с неопределенными переменными происходит столько же вызовов findall, сколько нашлось решений. findall как-то умудряется их аккамулировать — и записать в список List. Но главное, получая управление кучу раз, findall вызвращает его всего 1 раз! КАК?!У первого, sum([A, B, C, D], #=, N), — бесконечное множество возможных решений, то есть уже на этой стадии программа зависнет.
?- sum([A,B,C,D], #=, 19).
A+B+C+D#=19.
Пролог просто не знает решения на этой стадии. Может, классический пролог и вис, не знаю.Но вот дальше и происходит полная магия! К моменту вызова findall([A, B, C, D], label([A, B, C, D]), List) все 4 переменные, A, B, C и D — уже имеют свои фиксированные значения.
?- sum([A,B,C,D], #=, 19),
| [A,B,C,D] ins 1..6.
A in 1..6,
A+B+C+D#=19,
B in 1..6,
C in 1..6,
D in 1..6.Нет. На этой стадии у пролога на руках всё ещё только набор фактов.?- sum([A,B,C,D], #=, 19),
[A,B,C,D] ins 1..6,
| findall([A, B, C, D], label([A, B, C, D]), List).
List = [[1, 6, 6, 6], [2, 5, 6, 6], [2, 6, 5, 6], [2, 6, 6, 5], [3, 4, 6, 6], [3, 5, 5|...], [3, 5|...], [3|...], [...|...]|...],
A in 1..6,
A+B+C+D#=19,
B in 1..6,
C in 1..6,
D in 1..6.
А вот теперь есть список всех значений, подходящих под предыдущие условия.?- sum([A,B,C,D], #=, 19), [A,B,C,D] ins 1..6, findall([A,B,C,D], label([A, B, C, D]), List), length(List, Len), random(0, Len, I), nth0(I, List, Elt).
<...>
Elt = [6, 6, 3, 4],
<...>
?- sum([A,B,C,D], #=, 19), [A,B,C,D] ins 1..6, findall([A,B,C,D], label([A, B, C, D]), List), length(List, Len), random(0, Len, I), nth0(I, List, Elt).
<...>
Elt = [5, 6, 2, 6],
<...>
?- sum([A,B,C,D], #=, 19), [A,B,C,D] ins 1..6, findall([A,B,C,D], label([A, B, C, D]), List), length(List, Len), random(0, Len, I), nth0(I, List, Elt).
<...>
Elt = [6, 6, 1, 6],
<...>
Действительно, сложностей в переборе 6^4 вариантов и присвоении их 4м переменным нет.
N = 18, sum([A, B, C, D], #=, N), [A, B, C, D] ins 0..sup., (sup = +бесконечность), то пролог сократит домены решений до 0..18:A in 0..18,
B in 0..18,
C in 0..18,
D in 0..18.
A in 1..2,
B in 1..2,
C in 1..2,
D in 1..2.
?- N = 5, sum([A, B, C, D], #=, N), [A, B, C, D] ins 1..6, findall([A, B, C, D], indomain(A), List).
N = 5,
List = [[1, _G419, _G422, _G425], [2, 1, 1, 1]],
A in 1..2,
A+B+C+D#=5,
B in 1..2,
C in 1..2,
D in 1..2,
_G419 in 1..2,
1+_G419+_G422+_G425#=5,
_G422 in 1..2,
_G425 in 1..2.
Разделить число на заданное количество кубиков