RPG attributes generator: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added rusty C++ solution)
mNo edit summary
Line 83: Line 83:
</pre>
</pre>


=={{header|c++}}==
=={{header|C++}}==
GCC 4.9.2, unoptimised.
GCC 4.9.2, unoptimised.
<lang C++>#include <algorithm>
<lang C++>#include <algorithm>

Revision as of 20:56, 19 July 2018

RPG attributes generator is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

You're running a tabletop RPG, and your players are creating characters.

Each character has six core attributes: strength, dexterity, constitution, intelligence, wisdom, and charisma.

One way of generating values for these attributes is to roll four, 6-sided dice (d6) and sum the three highest rolls, discarding the lowest roll.

Some players like to assign values to their attributes in the order they're rolled.

To ensure generated characters don't put players at a disadvantage, the following requirements must be satisfied:

  • The total of all character attributes must be at least 75.
  • At least two of the attributes must be at least 15.

However, this can require a lot of manual dice rolling. A programatic solution would be much faster.

Task

Write a program that:

  1. Generates 4 random, whole values between 1 and 6.
  2. Saves the sum of the 3 largest values.
  3. Generates a total of 6 values this way.
  4. Displays the total, and all 6 values once finished.

  • The order in which each value was generated must be preserved.
  • The total of all 6 values must be at least 75.
  • At least 2 of the values must be 15 or more.

C

Translation of: Go

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <time.h>

int compareInts(const void *i1, const void *i2) {

   int a = *((int *)i1);
   int b = *((int *)i2);
   return a - b;

}

int main() {

   int i, j, nsum, vsum, vcount, values[6], numbers[4];
   srand(time(NULL));
   for (;;) {
       vsum = 0;
       for (i = 0; i < 6; ++i) {
           for (j = 0; j < 4; ++j) {
               numbers[j] = 1 + rand() % 6;
           }
           qsort(numbers, 4, sizeof(int), compareInts);
           nsum = 0;
           for (j = 1; j < 4; ++j) {
               nsum += numbers[j];
           }
           values[i] = nsum;
           vsum += values[i];
       }
       if (vsum < 75) continue;
       vcount = 0;
       for (j = 0; j < 6; ++j) {
           if (values[j] >= 15) vcount++;
       }
       if (vcount < 2) continue;
       printf("The 6 random numbers generated are:\n");
       printf("[");
       for (j = 0; j < 6; ++j) printf("%d ", values[j]);
       printf("\b]\n");
       printf("\nTheir sum is %d and %d of them are >= 15\n", vsum, vcount);
       break;
   }
   return 0;

}</lang>

Output:

Sample run:

The 6 random numbers generated are:
[9 15 15 17 13 8]

Their sum is 77 and 3 of them are >= 15

C++

GCC 4.9.2, unoptimised. <lang C++>#include <algorithm>

  1. include <ctime>
  2. include <iostream>
  3. include <cstdlib>
  4. include <string>

using namespace std;

int main() {

   srand(time(0));
   
   unsigned int attributes_total = 0;
   unsigned int count = 0;
   int attributes[6] = {};
   int rolls[4] = {};
   
   while(attributes_total < 75 || count < 2)
   {
       attributes_total = 0;
       count = 0;
       
       for(int attrib = 0; attrib < 6; attrib++)
       {            
           for(int roll = 0; roll < 4; roll++)
           {
               rolls[roll] = 1 + (rand() % 6);
           }
           
           sort(rolls, rolls + 4);
           int roll_total = rolls[1] + rolls[2] + rolls[3];            
                       
           attributes[attrib] = roll_total;
           attributes_total += roll_total;
           
           if(roll_total >= 15) count++;
       }
   }
   
   cout << "Attributes generated : [";
   cout << attributes[0] << ", ";
   cout << attributes[1] << ", ";
   cout << attributes[2] << ", ";
   cout << attributes[3] << ", ";
   cout << attributes[4] << ", ";
   cout << attributes[5];
   
   cout << "]\nTotal: " << attributes_total;
   cout << ", Values above 15 : " << count;
   
   return 0;

}</lang>

Go

<lang go>package main

import (

   "fmt"
   "math/rand"
   "sort"
   "time"

)

func main() {

   s := rand.NewSource(time.Now().UnixNano())
   r := rand.New(s)
   for {
       var values [6]int
       vsum := 0
       for i := range values {
           var numbers [4]int
           for j := range numbers {
               numbers[j] = 1 + r.Intn(6)
           }
           sort.Ints(numbers[:])
           nsum := 0
           for _, n := range numbers[1:] {
               nsum += n
           }
           values[i] = nsum
           vsum += values[i]
       }
       if vsum < 75 {
           continue
       }
       vcount := 0
       for _, v := range values {
           if v >= 15 {
               vcount++
           }
       }
       if vcount < 2 {
           continue
       }
       fmt.Println("The 6 random numbers generated are:")
       fmt.Println(values)
       fmt.Println("\nTheir sum is", vsum, "and", vcount, "of them are >= 15")
       break
   }

}</lang>

Output:

Sample run:

The 6 random numbers generated are:
[16 15 7 14 9 15]

Their sum is 76 and 3 of them are >= 15

JavaScript

<lang javascript>function roll() {

 const stats = {
   total: 0,
   rolls: []
 }
 let count = 0;
 for(let i=0;i<=5;i++) {
   let d6s = [];
   for(let j=0;j<=3;j++) {
     d6s.push(Math.ceil(Math.random() * 6))
   }    
   d6s.sort().splice(0, 1);
   rollTotal = d6s.reduce((a, b) => a+b, 0);
   stats.rolls.push(rollTotal);
   stats.total += rollTotal; 
 }
 
 return stats;

}

let rolledCharacter = roll();

while(rolledCharacter.total < 75 || rolledCharacter.rolls.filter(a => a >= 15).length < 2){

 rolledCharacter = roll();

}

console.log(rolledCharacter.total, rolledCharacter.rolls.join(', ')); </lang>

Output:

Sample run:

80 "16, 15, 13, 13, 13, 10"

Kotlin

<lang scala>// Version 1.2.51

import java.util.Random

fun main(args: Array<String>) {

   val r = Random()
   while (true) {
       val values = IntArray(6)
       for (i in 0..5) {
           val numbers = IntArray(4) { 1 + r.nextInt(6) }
           numbers.sort()
           values[i] = numbers.drop(1).sum()
       }
       val vsum = values.sum()
       val vcount = values.count { it >= 15 }
       if (vsum < 75 || vcount < 2) continue
       println("The 6 random numbers generated are:")
       println(values.asList())
       println("\nTheir sum is $vsum and $vcount of them are >= 15")
       break
   }

}</lang>

Output:

Sample run:

The 6 random numbers generated are:
[13, 14, 13, 15, 17, 8]

Their sum is 80 and 2 of them are >= 15

Perl 6

Works with: Rakudo Star version 2018.04.1

<lang perl6>sub heroic_attr { + @^a.grep: * >= 15 }

my @attr; repeat until @attr.sum >= 75 and heroic_attr(@attr) >= 2 {

   @attr = map { (1..6).roll(4).sort(+*).skip(1).sum }, ^6;

}

say @attr; say "Sum: {@attr.sum}, with {heroic_attr(@attr)} attributes >= 15";</lang>

Output:
[15 17 13 10 10 15]
Sum: 80, with 3 attributes >= 15

PHP

<lang php><?php

$attributesTotal = 0; $count = 0;

while($attributesTotal < 75 || $count < 2) {

   $attributes = [];
   
   foreach(range(0, 5) as $attribute) {
       $rolls = [];
       
       foreach(range(0, 3) as $roll) {
           $rolls[] = rand(1, 6);
       }
       
       sort($rolls);
       array_shift($rolls);
       
       $total = array_sum($rolls);
       
       if($total >= 15) {
           $count += 1;
       }
       
       $attributes[] = $total;
   }
   
   $attributesTotal = array_sum($attributes);

}

print_r($attributes);</lang>

Python

Python: Simple

<lang python>import random random.seed() attributes_total = 0 count = 0

while attributes_total < 75 or count < 2:

   attributes = []
   for attribute in range(0, 6):
       rolls = []
       
       for roll in range(0, 4):
           result = random.randint(1, 6)
           rolls.append(result)
       
       sorted_rolls = sorted(rolls)
       largest_3 = sorted_rolls[1:]
       rolls_total = sum(largest_3)
       
       if rolls_total >= 15:
           count += 1
       
       attributes.append(rolls_total)
   attributes_total = sum(attributes)
   

print(attributes_total, attributes)</lang>

Output:

Sample run:

(74, [16, 10, 12, 9, 16, 11])

Python: Nested List Comprehensions

<lang python>import random random.seed() total = 0 count = 0

while total < 75 or count < 2:

   attributes = [(sum(sorted([random.randint(1, 6) for roll in range(0, 4)])[1:])) for attribute in range(0, 6)]    
  
   for attribute in attributes:
       if attribute >= 15:
           count += 1
  
   total = sum(attributes)
   

print(total, attributes)</lang>

Output:

Sample run:

(77, [17, 8, 15, 13, 12, 12])

REXX

<lang rexx>/* REXX Generates 4 random, whole values between 1 and 6. Saves the sum of the 3 largest values. Generates a total of 6 values this way. Displays the total, and all 6 values once finished.

  • /

Do try=1 By 1

 ge15=0
 sum=0
 ol=
 Do i=1 To 6
   rl=
   Do j=1 To 4
     rl=rl (random(5)+1)
     End
   rl=wordsort(rl)
   rsum.i=maxsum()
   If rsum.i>=15 Then ge15=ge15+1
   sum=sum+rsum.i
   ol=ol right(rsum.i,2)
   End
 Say ol '->' ge15 sum
 If ge15>=2 & sum>=75 Then Leave
 End

Say try 'iterations' Say ol '=>' sum Exit

maxsum: procedure Expose rl /**********************************************************************

  • Comute the sum of the 3 largest values
                                                                                                                                            • /
 m=0
 Do i=2 To 4
   m=m+word(rl,i)
   End
 Return m

wordsort: Procedure /**********************************************************************

  • Sort the list of words supplied as argument. Return the sorted list
                                                                                                                                            • /
 Parse Arg wl
 wa.=
 wa.0=0
 Do While wl<>
   Parse Var wl w wl
   Do i=1 To wa.0
     If wa.i>w Then Leave
     End
   If i<=wa.0 Then Do
     Do j=wa.0 To i By -1
       ii=j+1
       wa.ii=wa.j
       End
     End
   wa.i=w
   wa.0=wa.0+1
   End
 swl=
 Do i=1 To wa.0
   swl=swl wa.i
   End
 Return strip(swl)</lang>
Output:
I:\>rexx cast
 13 13  8 15 14 11 -> 1 74
 10  9 13  7 15  9 -> 1 63
 15 15 14 13 17 14 -> 3 88
3 iterations
 15 15 14 13 17 14 => 88

zkl

<lang zkl>reg attrs=List(), S,N; do{

  attrs.clear();
  do(6){
     abcd:=(4).pump(List(),(0).random.fp(1,7)); // list of 4 [1..6] randoms
     attrs.append(abcd.sum(0) - (0).min(abcd)); // sum and substract min
  }

}while((S=attrs.sum(0))<75 or (N=attrs.filter('>=(15)).len())<2); println("Random numbers: %s\nSum to %d, number over 15: %d"

       .fmt(attrs.concat(","),S,N));</lang>
Output:
Random numbers: 16,16,13,14,16,11
Sum to 86, number over 15: 3