Choose the Most Dramatic Outcome

4

1

The premise of this is simple: A 10% chance is pretty unlikely, but everyone knows that a one-in-a-million chance is a sure thing!

So, write code that implements the following "dramatic" probability rules:

  • Take in a floating point P from 0 to 1 representing the unmodified chance of some plot-related event, and a boolean representing whether we're in the climax or not.
  • Determine P' on these conditions:
    • If 0 < P &leq; 10-3 then P' = 1.
    • If .999 &leq; P < 1 then P' = 0.
    • If P = 0 and we're in the climax, then the heroes will likely get a last-minute sudden advantage and P' = .9.
    • If P = 1 and we're in the climax, then the villain will unveil an as-yet-unseen superweapon and P' = .1.
    • Otherwise, P' = P.
  • Return truthy or falsey based on P' as the chance of truth. For example, if P' = .7, then you should return truthy 70% of the time and falsey 30% of the time.

Shortest code in bytes wins!

Nissa

Posted 2018-10-25T17:58:46.950

Reputation: 3 334

See also Million-to-one chance quote.

– Neil – 2018-10-25T19:42:20.073

1@Neil Discworld has literal Random Number Gods? – Nissa – 2018-10-25T19:44:36.227

Discworld has all possible Gods, but only the ones that get believed in have any power. – Neil – 2018-10-25T19:49:31.700

3Alternative title: "Does your language have a terse if-else ternary operator?" – ngm – 2018-10-25T20:27:56.630

Answers

0

05AB1E,  44  42 bytes

Crossed out &nbsp;44&nbsp; is no longer 44 :)

_i90*ë¹₄*©1›i1₄®-‹i¹т*ë¹iiTëтë0ëт]5°<Ý₄/Ω›

Port of my Java 8 answer. First input is P, second input is 0/1 for truthy/falsey whether there is a climax.

Try it online.

Explanation:

_i                     # If the first (implicit) input is exactly 0:
  90                   #  Push 90
    *                  #  Multiply it with the second (implicit) input (0 if 0, 90 if 1)
 ë                     # Else:
  ¹₄*                  #  Push the first input, and multiply it by 1000
     ©                 #  Save it in the register (without popping)
      1›i              #  If it's larger than 1 (so input larger than 0.001):
          ₄®-          #   Push 1000, and subtract the value from the register
         1   ‹i        #   If it's smaller than 1 (so input smaller than 0.999):
               ¹т*     #    Push the first input multiplied by 100
              ë        #   Else:
               ¹i      #    If the first input is exactly 1:
                 i     #     If the second (implicit) input is 1:
                  T    #      Push 10
                 ë     #     Else:
                  т    #      Push 100
                ë      #    Else:
                 0     #     Push 0
          ë            #  Else:
           т           #   Push 100
   ]                   # Close all if-else clauses
    5°                 # Push 100000 (10**5)
      <                # Decrease it by 1: 99999
       Ý               # Create a list in the range [0,99999]
        ₄/             # Divide it by 1000: [0,0.001,0.002,...,99.997,99.998,99.999]
          Ω            # Take a random value from the list
           ›           # Check if the earlier value is larger than this random value
                       # (and output implicitly)

05AB1E has no builtin for a random decimal value in the range [0, 1), so I use 5°<Ý₄/ to generate a list in the range [0,99.999] in steps of 0.001 and then Ω to take a random value from that list (and I use percentages [0, 100] instead of decimals [0, 1] in the rest of my code).

Kevin Cruijssen

Posted 2018-10-25T17:58:46.950

Reputation: 67 575

1

R, 86 bytes

function(a,b,d=a*(1-a))runif(1)<="if"(d,"if"(d>999e-6,a,1-round(a)),"if"(b,.9-.8*a,a))

Try it online!

a is P' and b is 1 or 0 for "in the climax" or not.

If a is 0 or 1, then d will be 0, in which case if b is 0 just return a, otherwise .9 minus .8*a.

Otherwise if a is not near 0 or 1, d will be "far" from 0 so return a. Otherwise 1-round(a) will take a to the "opposite" 0 or 1.

Then see if a random selection from [0,1] is less than or equal to the resulting probability.

The link does a little simulation for all the possible scenarios to demonstrate that it all seems to work.

ngm

Posted 2018-10-25T17:58:46.950

Reputation: 3 974

Where did you get the 999e-6 from? – Nissa – 2018-10-25T18:48:56.643

Since 0 <= a <= 1, d will be bigger than 999e-6 = 0.000999 exactly when a < 0.001 or a > 0.999. – ngm – 2018-10-25T18:52:54.573

Huh, I was wondering how you could take advantage of the symmetry in the sandbox, you seem to have figured it out. – Nissa – 2018-10-25T18:58:20.510

Also, you can save bytes on parentheses by setting d to a-a*a. – Nissa – 2018-10-25T18:59:40.627

1

C (gcc), 82 bytes

Zero bytes of source code. Use the preprocessor directive:

-Df(p,c)=rand()<~(1<<31)*(c&p==0?.9:p==1&c?.1:(p<=1e-3|p>=.999)&p!=1&p!=0?p<.1:p)

Try it online!

Very little to explain about it; p is the probability, c the climax boolean. Main golfing trick is ~(1<<31), which seems to be the equivalent to RAND_MAX for gcc. The usual C golfing tricks go straight out the window with floating points.

user77406

Posted 2018-10-25T17:58:46.950

Reputation:

1

Java 8, 65 bytes

P->C->Math.random()<(P==0?C?.9:0:P>.001?P<.999?P:P==1?C?.1:1:0:1)

Try it online.

Explanation:

We have the following scenario combinations to consider:

P=0, C=falsey             → 100% falsey
P=0, C=truthy             → 90% truthy; 10% falsey
P=(0,0.001], C=either     → 100% truthy
P=(0.001,0.999), C=either → (P*100)% truthy; (100-P*100)% falsey
P=[0.999,1), C=either     → 100% falsey
P=1, C=truthy             → 10% truthy; 90% falsey
P=1, C=falsey             → 100% truthy

Which gives us the following code:

P->C->           // Method with double and boolean parameters and boolean return-type
  Math.random()  //  Random value in the range [0, 1)
   <(P==0?       //  If P is 0:
      C?         //   And there is a climax:
       .9        //    Check if the random value is smaller than 0.9 (90% true)
      :          //   Else:
       0         //    Check if the random value is smaller than 0 (0% true)
    :P>.001?     //  Else-if P is larger than 0.001:
      P<.999?    //   If P is smaller than 0.999, so in range (0.001,0.999):
       P         //    Check if the random value is smaller than P (P*100% true)
      :P==1?     //   Else-if P is 1:
       C?        //    And there is a climax:
        .1       //     Check if the random value is smaller than 0.1 (10% true)
       :         //    Else:
        1        //     Check if the random value is smaller than 1 (100% true)
      :          //   Else, so P is in the range [0.999,1):
       0         //    Check if the random value is smaller than 0 (0% true)
    :            //  Else, so P is in the range (0,0.001]:
     1)          //   Check if the random value is smaller than 1 (100% true)

Kevin Cruijssen

Posted 2018-10-25T17:58:46.950

Reputation: 67 575

1

Perl 6, 54 bytes

{(($/=1-$^p min$p)??.001>=$/||$/!!$^c*.9)>rand^^$p>.5}

Try it online!

Explanation

{
 (
  ($/=1-$^p min$p)    # Compute min(p,1-p) and store in $/
  ??                  # if $/ > 0
    .001>=$/||        #   if $/ <= 0.001 then 1
    $/                #   else $/
  !!$^c*.9            # else 0.9 * climax
 )>rand               # Random Bool with given probability
 ^^$p>.5              # Flip if p > 0.5
}

nwellnhof

Posted 2018-10-25T17:58:46.950

Reputation: 10 037

0

Perl 5 -pl, 61 bytes

$_=(!$_?<>?.9:0:$_==1?<>?.1:1:$_<=.001||($_<.999&&$_))>rand<>

Try it online!

Input is on two lines. First line is P; second line is 0 if not in climax, 1 if in climax.

Xcali

Posted 2018-10-25T17:58:46.950

Reputation: 7 671

0

Python 3, 118 bytes

from random import *
def f(p,c):
if c:
 if p==1:p=.9
 if p==0:p=.1
if p<1e-3:p=1
if p>.999:p=0
return random()<p

Inputs: p is initial probability, c is climax

Hannes Karppila

Posted 2018-10-25T17:58:46.950

Reputation: 3 090