简体   繁体   中英

Sum of random digits in Prolog

The scenario is to mimic rolling 3 six-sided die in Prolog while trying to obey the recursive nature of prolog. This is easily done with the Fibonacci series

n_factorial(N, F) :- 
  N #> 0,
  F #= N*F1,
  N1 #= N-1,
  n_factorial(N1, F1).

I'm having difficulty translating this to the dice paradigm, where we add a random number to the sum.

# N = number of dice, S = number of sides, R = result
roll_dice(N, S, R) :-  
  N1 #> 0,
  R = random_between(1, S, R1),
  N1 #= N-1,
  roll_dice(N1, S, R1).

throws an error but neglects the sum anyway. I would normally use += in other languages.

A few things not quite right there:

  • R = random_between(1, S, R1) stores that structure in R, it does not generate random numbers.

  • R1 is used for "the random number you get for rolling one die" and "the sum of all the random numbers from rolling all the remaining dice" and it is unlikely those will be the same value, and when they isn't the same, that will fail.

  • There is no code to do the summing. (The equivalent of the Factorial video using F #= N * F1 )

  • No recursive base case (the first line of the factorial from the video is not shown in your question, it is n_factorial(0, 1). ). When N dice remaining gets down to 0, there is nothing to handle that case.

Here is one implementation:

:- use_module(library(clpfd)).

roll_dice(0, _, 0).

roll_dice(NDice, Sides, Sum) :-  
  NDice #> 0,

  random_between(1, Sides, Roll),
  Sum #= Roll + RunningTotal,

  NDiceLeft #= NDice - 1,
  roll_dice(NDiceLeft, Sides, RunningTotal).

while trying to obey the recursive nature of Prolog.

I guess that's important to understand; this can be done with less bolierplate and fewer temporary variables to name, eg:

roll_dice(NDice, Sides, Sum) :-  
    length(Rolls, NDice),
    maplist(random(1, Sides), Rolls),
    sum_list(Rolls, Sum).

which makes a list Rolls the right size to hold all the rolls, fills them in using maplist to apply random on each of them, and sums that list for the answer.

I'd do something along the lines of:

roll(N,S,R) :- positive_int(N), positive_int(S), roller(N,S,0,R) .

positive_int(N) :- integer(N), N > 0 .

roller(0,_,R,R) .
roller(N,S,T,R) :-
  T1 is 1+random(S),
  N1 is N-1,
  roller(N1,S,T1,R)
  .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM