# Introduction

In tabletop games like Dungeons and Dragons, when you begin a battle, all involved parties roll for initiative. In DnD 5e, this is 1d20 + DEX + Other bonuses, where DEX is the bonus given by your Dexterity stat. The characters that roll higher numbers go first. We'll use a similar, deterministic system in this challenge.

# The Challenge

Write a program or function that, when given a list of characters, will output a list of characters in order of initiative.

A character is defined as this:

character = {
name: "name" // a string
statblock: [SPD, DEX, WHT] // a list of numbers
// DEX = dexterity, SPD = speed, WHT = weight
}


The formula for initiative is the following: $$\text{Initiative} = \left\lfloor{ \frac{\text{SPD}^2}{\sqrt{\lvert\text{DEX}\rvert}} }\right\rfloor - \text{WHT}$$

# Input

A list of characters, unsorted. This can be a JSON object, a list of lists, a list of dictionaries, a series of strings etc.

It is guaranteed that all names will be unique.

# Output

A list of characters, or character names, sorted by initiative order from highest to lowest, based on the above formula.

# Sample IO

Input --> Output
[[Name, SPD, DEX, WHT], ...]
--> [[Name, SPD, DEX, WHT], ...] (or [Name, Name, ...])
---------
[[Alice,1,2,3],[Bob,10,5,0],[Charlie,3,2,1]]
--> [Bob, Charlie, Alice]
// Alice = -3, Bob = 44, Charlie = 5

[[Z,1,1,1],[B,1,1,1],[XY,5,1,1]]
--> [XY, Z, B]
// Retain the order of characters from the input if they have the same initiative.
// Z = 0, B = 0, XY = 24

[[Neg,-3,-3,-1],[SomeNeg,5,-2,-4],[NoNeg,4,6,8]]
--> [SomeNeg, Neg, NoNeg]
// Negative values are valid.
// Neg = 6, SomeNeg = 21, NoNeg = -2

[[Flo,1.5,2.5,3.5],[MoreFlo,2,2.5,3.5]]
--> [[MoreFlo,2,2.5,3.5], [Flo,1.5,2.5,3.5]]
// Floats are also valid.
// Flo = -2.5, MoreFlo = -1.5

[[Lonely,1,2,3]]
--> [[Lonely,1,2,3]]
// Input with 1 item.

[]
--> []
// Empty input leads to empty output.

[[Foo,2,1,4], [Baz,5,5,4], [Bar,5,1,4]]
--> [Bar, Baz, Foo]
// Foo = 0, Bar = 21, Baz = 7

[['Adam', 2, 4, 1], ['Eve', 2, 3, 1]]
// Adam = 2, Eve = 2
// If you do not floor, you'll end up with [Eve, Adam] (Adam = 2, Eve ~= 2.3)


• Curious - where did this initiative formula come from? – Quintec Dec 8 '19 at 16:52
• Something I came up with on the fly while writing this, it's not really based on anything. – bigyihsuan Dec 8 '19 at 17:12
• So it is. Thanks for catching it! – bigyihsuan Dec 8 '19 at 19:48
• Can we sort the input in place (i.e whatever is passed into the function will be sorted when the function finishes)? – Noodle9 Dec 8 '19 at 21:54
• So small dexterity is good here? – Paŭlo Ebermann Dec 9 '19 at 0:08

# JavaScript (ES7),  73  60 bytes

-13 bytes by just sorting the input without isolating the names, as suggested by @asgallant

Expects a list of [SPD, DEX, WHT, Name].

a=>a.sort((a,b)=>(g=([s,d,w])=>~(s*s/(d*d)**.25)+w)(a)-g(b))


Try it online!

### How?

To save a few bytes:

• we compute $$\-\text{Initiative}-1\$$ instead and sort the list the other way around
• we compute $$\\sqrt{|\text{DEX}|}\$$ as $$\(\text{DEX}^2)^{\frac{1}{4}}\$$
• Outputting a list of characters (not just their names) is valid according to the challenge, so you can save a few bytes by dropping the .map call. – asgallant Dec 9 '19 at 18:20

# 05AB1E, 10 8 bytes

ΣnsÄt÷-


Input in the format and order ["name", WHT, DEX, SPD], and output are the same inner lists sorted from highest to lowest initiative.

-2 bytes thanks to @Grimmy.

Explanation:

The sort builtin Σ sorts from lowest to highest by default, so I'm using the following modified formula to not only save bytes, but sort from highest to lowest at the same time with this builtin (thanks @Grimmy):
$$Initiative = WHT - \left\lfloor\frac{SPD^2}{\sqrt{\lvert DEX\rvert}}\right\rfloor$$

Σ         # Sort the (implicit) input-list by:
#  Pop and push all values of the inner list separated to the stack
n       #  Square the SPD at the top of the stack
s      #  Swap so the DEX is now at the top of the stack
Ä     #  Take its absolute value
t    #  Then its square-root
÷   #  And integer-divide the squared SPD by this
-  #  Subtract this from the WHT (to sort in descending instead of ascending order)
#  (after which the result is output implicitly)

• s-( can be just -. – Grimmy Dec 9 '19 at 13:10

# Japt, 20 18 bytes

ñÈÌ-(Xg1 ²/Xg2a ¬f


Try it

Simply calculates the formula for each character and sorts. Negates the formula to sort in the correct order.

Takes input as a list of lists [Name, SPD, DEX, WHT]. (I could save a byte taking input as [SPD, Name, DEX, WHT] but that feels cheaty.)

# Python 3, 63 59 bytes

lambda c:sorted(c,key=lambda x:x[3]-x[1]**2//abs(x[2]**.5))


Try it online!

Pretty straigtforward. Sorts by - initiative to get the right output order.

# Python 2, 60 56 bytes

lambda c:sorted(c,key=lambda(a,b,c,d):d-b*b//abs(c)**.5)


Try it online!

thanks to @Chas Brown

• In python2, you can shave off 2 bytes via unpacking. (This is one of the few things I don't like in Python 3). – Chas Brown Dec 8 '19 at 21:40
• I think you are supposed to return a list of just the names,not the entire records. – Galen Ivanov Dec 9 '19 at 10:14
• @GalenIvanov The Output section of the challenge specifies you can return the whole Character, or the characters name. This answer has chosen the first option. – Potato44 Dec 9 '19 at 10:41
• @Potato44 Yes, the Sample IO shows different possibilities. – Galen Ivanov Dec 9 '19 at 11:13
• @ChasBrown Thank you, I tried this because I thought I had seen it somewhere, but it resulted in an error and I didn't think that it could be 2-only. Got it to 60 with b**2 -> b*b. – Black Owl Kai Dec 9 '19 at 15:02

# K (oK), 28 bytes

f:{(!x)@>{-z-(x*x)%%y|-y}.'.x}


Try it online!

-10 thanks to ngn :-)

• (y;-1*y)0>y -> y|-y, %: -> %, (-z)+ -> -z- – ngn Feb 16 '20 at 5:34
• @ngn aghhh, the y sign switch was obviously doing too much work in my implementation. your solution seems to obvious in hindsight. i won't forget that! – scrawl Feb 16 '20 at 20:57

# Ruby, 44 bytes

->d{d.sort_by{|_,x,y,z|-x*x/y.abs()**1/2+z}}


Try it online!

-3 bytes thanks to @79037662

• You can get rid of the reverse by sorting "backwards": tio.run/##VczNC4IwHMbx@/6K4UnXb@qmRheD6t6l4xix@VIDS/… – 79037662 Dec 8 '19 at 20:17
• @79037662 thanks! Good point! I also got rid of some extra bytes by replacing indexing with variables! – game0ver Dec 8 '19 at 20:37
• See the last test case, which fails if you ignore DEX. – bigyihsuan Dec 9 '19 at 13:59
• No it doesn't, it gives Bar, Baz, Foo which is the test case... – game0ver Dec 9 '19 at 14:10

# APL+WIN, 41 bytes

Prompts for a n x 4 matrix where n is the number of rows 1 per character and the columns are Name, SPD, DEX, WHT. The output is a 1 column matrix of character names

m←⎕⋄⊃m[⍒⌊((m[;2]*2)÷(|m[;3])*.5)-m[;4];1]


Try it online!Courtesy of Dyalog Classic

# Red, 108 107 bytes

-1 byte thanks to raznagul

func[b][extract next sort/skip collect[foreach e
b[keep 0 -(e/2 ** 2 /(e/3 ** 2 ** .25)- e/4)keep e/1]]2 2]


Try it online!

• I don't know red, but shouldn't you be able to replace e/2 * e/2 with e/2 ** 2? – raznagul Dec 9 '19 at 13:16
• @raznagul Yes,of course. You can see that I did it for e/3 but apparently I forgot to apply it to e/2. Thanks! – Galen Ivanov Dec 9 '19 at 13:21

# Google Sheets, 49 37 bytes

-12 bytes thanks to Black Owl Kai

=Sort(A:A,D:D-B:B^2/Sqrt(Abs(C:C)),1)


Input is in the range A1:D with the four columns being player, speed, dexterity, and weight.

Explanation:
D:D-B:B^2/Sqrt(Abs(C:C)) do the math bit. The values are actually Initiaive * -1 so we can sort them ascending and get the order we want. Otherwise, all the blank rows would be sorted before the player names.
=Sort(A:A,~,1) sorts the player list based on the math bit output.

Test cases:

• =Sort(A:A;D:D-B:B^2/Sqrt(Abs(C:C));1) gets rid of the if – Black Owl Kai Dec 10 '19 at 8:40

# Jelly, 20 bytes

ḊA2¦U*Ø½j.¤UŒH:/€IµÞ


Try it online!

Well, this is horribly hacked together but it works. The Footer in the TIO link simply runs the code over each list then returns just the names. The code itself returns the names and all stats in the same format as the input, namely [Name, SPD, DEX, WHT]

Will post an explanation after any more golfing

# Charcoal, 36 bytes

ＦＡ⊞υ⟦⁻⌊∕Ｘ⊟ι²₂↔⊟ι⊟ι⊟ι⟧Ｗ⌈υ«≔Φυ¬⁼ικυ⟦⊟ι


Try it online! Takes quadruples in the order name, weight, speed, dexterity. Explanation:

ＦＡ


⊞υ⟦⁻⌊∕Ｘ⊟ι²₂↔⊟ι⊟ι⊟ι⟧


Square the dexterity, floor divide by the square rooted absolute speed and subtract the weight, then create a tuple with the result and the name and push that to the predefined list.

Ｗ⌈υ«


While there are still tuples in the list, take the maximum.

≔Φυ¬⁼ικυ


Remove the tuple from the list.

⟦⊟ι


Output the name on its own line.

ṛ²:A½$}ɗ_@3ƭ/Þ  Try it online! A monadic link that takes a list of characters as its argument. Each list is structured as [Name, SPD, DEX, WHT]. Returns a list of characters in the desired order. # Python 3.8, 81 bytes This solution uses the formula as described in the question. As input a dictionary is expected in the following form: {"name":[SPD, DEX, WHT],...} lambda d:sorted(n:={_:(i:=-a*a/abs(b)**.5+c)for _,(a,b,c)in d.items()},key=n.get)  Try it online! • See the last test case, which fails if you ignore DEX. – bigyihsuan Dec 9 '19 at 13:58 • No it doesn't, it gives Bar, Baz, Foo which is the test case... – game0ver Dec 9 '19 at 14:11 # APL(NARS), chars 40, bytes 80 {⍵≡⍬:⍬⋄↑¨⍵[⍒{(4⊃⍵)-⍨⌊(2*⍨2⊃⍵)÷√∣3⊃⍵}¨⍵]}  test:  f←{⍵≡⍬:⍬⋄↑¨⍵[⍒{(4⊃⍵)-⍨⌊(2*⍨2⊃⍵)÷√∣3⊃⍵}¨⍵]} ⎕fmt ,⊂(('Lonely') 1 2 3) ┌1────────────────┐ │┌4──────────────┐│ ││┌6──────┐ ││ │││ Lonely│ 1 2 3││ ││└───────┘ ~ ~ ~2│ │└∊──────────────┘3 └∊────────────────┘ ⎕fmt f,⊂(('Lonely') 1 2 3) ┌1────────┐ │┌6──────┐│ ││ Lonely││ │└───────┘2 └∊────────┘ ⎕fmt (('Alice') 1 2 3)(('Bob') 10 5 0)(('Charlie') 3 2 1) ┌3──────────────────────────────────────────────────┐ │┌4─────────────┐ ┌4────────────┐ ┌4───────────────┐│ ││┌5─────┐ │ │┌3───┐ │ │┌7───────┐ ││ │││ Alice│ 1 2 3│ ││ Bob│ 10 5 0│ ││ Charlie│ 3 2 1││ ││└──────┘ ~ ~ ~2 │└────┘ ~~ ~ ~2 │└────────┘ ~ ~ ~2│ │└∊─────────────┘ └∊────────────┘ └∊───────────────┘3 └∊──────────────────────────────────────────────────┘ ⎕fmt f (('Alice') 1 2 3)(('Bob') 10 5 0)(('Charlie') 3 2 1) ┌3─────────────────────────┐ │┌3───┐ ┌7───────┐ ┌5─────┐│ ││ Bob│ │ Charlie│ │ Alice││ │└────┘ └────────┘ └──────┘2 └∊─────────────────────────┘ ⎕fmt f ('Z' 1 1 1)('B' 1 1 1)(('XY') 5 1 1) ┌3────────┐ │┌2──┐ │ ││ XY│ Z B│ │└───┘ ¯ ¯2 └∊────────┘ ⎕fmt f (('Neg') ¯3 ¯3 ¯1)(('SomeNeg') 5 ¯2 ¯4)(('NoNeg') 4 6 8) ┌3─────────────────────────┐ │┌7───────┐ ┌3───┐ ┌5─────┐│ ││ SomeNeg│ │ Neg│ │ NoNeg││ │└────────┘ └────┘ └──────┘2 └∊─────────────────────────┘ ⎕fmt f ⍬ ┌0─┐ │ 0│ └~─┘ ⎕fmt f (('Flo') 1.5 2.5 3.5)(('MoreFlo') 2 2.5 3.5) ┌2────────────────┐ │┌7───────┐ ┌3───┐│ ││ MoreFlo│ │ Flo││ │└────────┘ └────┘2 └∊────────────────┘ ⎕fmt f (('Foo') 2 1 4)(('Baz') 5 5 4)(('Bar') 5 1 4) ┌3───────────────────┐ │┌3───┐ ┌3───┐ ┌3───┐│ ││ Bar│ │ Baz│ │ Foo││ │└────┘ └────┘ └────┘2 └∊───────────────────┘ ⎕fmt f (('Adam') 2 4 1)(('Eve') 2 3 1) ┌2─────────────┐ │┌4────┐ ┌3───┐│ ││ Adam│ │ Eve││ │└─────┘ └────┘2 └∊─────────────┘  # Perl 5-n, 72 bytes sub i{int($_[1]**2/sqrt abs$_[2])-pop}say$$_[0]for sort{i(@$b)-i@\$a}eval


Try it online!

# C++ (clang), 324 $$\\cdots\$$ 232 204 bytes

Saved 18 46 bytes thanks to cielingcat!!!

#import<regex>
#import<cmath>
#define i(s)int(*s**s/sqrt(abs(s[1])))-s[2]
struct C{std::string n;float s[3];};void f(std::vector<C>&v){std::stable_sort(&v[0],&*end(v),[](C a,C b){return i(a.s)>i(b.s);});}


Try it online!

# Ungolfed:

#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;

struct C {
string n;
float s[3];
};
float i(C c) {
return floor(c.s[0]*c.s[0] / sqrt(abs(c.s[1]))) - c.s[2];
}
void f(vector<C>&v) {
stable_sort(begin(v), end(v),
[](C a,C b) {
return i(a) > i(b);
});
}

• @ceilingcat Very nice - thanks! :-) – Noodle9 Feb 27 '20 at 1:13