# Which electrical outlets can I use?

In North America, most electrical outlets/receptacles follow standards set by NEMA. For this challenge, you'll be given a few properties of a device you need to plug in, and your program (or function) should return all of the outlets that would be compatible.

For this challenge, an outlet has three properties: voltage, current rating, and grounding.

I/O:

Input will consist of a voltage, current usage, and grounding requirements for some device. The first two are positive integers, and the third can be represented by a boolean (though you are allowed to represent it in any reasonable way).

The output should be a list of outlets which are compatible, following the rules below. Each outlet's name is formatted as NN-nn, with NN and nn being numbers. All outlets should either be returned as strings with this formatting, or arrays of [NN, nn]. You can return the compatible outlets in an array, or separated with spaces/newlines/commas, or via any other reasonable method.

Requirements:

In order for an outlet to be compatible with the inputted device, it must meet three requirements:

• The voltage should be within ±10% of the device's voltage
• The current rating should be at least as high as the device's current usage
• If the device requires a grounded outlet, the outlet must be grounded (otherwise it may or may not be)

Outlets:

These are the outlets your program must be able to handle:

1-15     120    15
2-15     240    15
2-20     240    20
2-30     240    30
5-15     120    15    G
5-20     120    20    G
5-30     120    30    G
6-15     240    15    G
6-20     240    20    G
6-30     240    30    G
6-50     240    50    G
7-15     277    15    G
7-20     277    20    G
7-30     277    30    G
7-50     277    50    G
10-30    240    30
10-50    240    50
11-20    240    20
11-30    240    30
11-50    240    50
12-20    480    20
14-15    240    15    G
14-30    240    30    G
14-50    240    50    G
14-60    240    60    G


The first column is the name of the outlet, followed by the voltage, then the current rating, then a G if it's grounded. Some of these may be slightly inaccurate.

Test Cases:

Formatted with a voltage, then current usage, then a G for grounded or an x for ungrounded. Some do not have any compatible outlets.

120    16    G    5-20, 5-30
260    5     x    2-15, 2-20, 2-30, 6-15, 6-20, 6-30, 6-50, 7-15, 7-20, 7-30, 7-50, 10-30, 10-50, 11-20, 11-30, 11-50, 14-15, 14-30, 14-50, 14-60
260    5     G    6-15, 6-20, 6-30, 6-50, 7-15, 7-20, 7-30, 7-50, 14-15, 14-30, 14-50, 14-60
260    35    x    6-50, 7-50, 10-50, 11-50, 14-50, 14-60
480    10    x    12-20
108    10    x    1-15, 5-15, 5-20, 5-30
528    20    x    12-20
249    50    G    6-50, 14-50, 14-60
250    50    G    6-50, 7-50, 14-50, 14-60
304    10    x    7-15, 7-20, 7-30, 7-50
480    10    G
480    25    x
400    10    x
600    10    x
180    10    x
80     10    x


Other:

This is , so shortest answer in bytes per language wins!

• Can we take input as an array ([voltage,current,grounding])? – A username Mar 27 at 8:30
• @Ausername Sure, the order/method which you take those three don't matter at all, as long as their reasonable. – Redwolf Programs Mar 27 at 16:54
• Minor complaint: your data makes NEMA 14 outlets equivalent to NEMA 6 ones, but actual NEMA 14 outlets can provide both 120V and 240V, unlike NEMA 6, and there's also a missing distinction between single-phase and 3-phase. – Joseph Sible-Reinstate Monica Apr 11 at 3:32
• @JosephSible-ReinstateMonica I considered adding some rules to account for those, but I didn't want to make the challenge overly complicated. – Redwolf Programs Apr 11 at 15:17

# JavaScript (ES10), 159 bytes

Same logic as my original answer, but with the data stored as a string with several unprintable characters.

(v,r,g)=>[..."_Î^~248ÕScž"].flatMap(x=>(x=x.charCodeAt(),n+=x>>6,V=(120<<x/16%4)%683,R=~(x/2&7)*10%65,-R<r|x&g|(V-v)**2>V*V/100?[]:n+[R]),n=1)


Try it online!

# JavaScript (ES10),  200 190 186  181 bytes

Expects (voltage, current, ground), where ground is a Boolean value. Returns an array of strings in NN-nn format.

(v,r,g)=>"0F5F1315CE02045E1214187E323438D519531519639E14181A".match(/../g).flatMap(x=>(x='0x'+x,n+=x>>6,V=(120<<x/16%4)%683,R=~(x/2&7)*10%65,-R<r|x&g|(V-v)**2>V*V/100?[]:n+[R]),n=1)


Try it online!

## How?

### Encoding format

Each outlet is encoded as a byte x whose bit-mask is DDVVRRRG with:

• DD = difference between the leading outlet ID and the previous leading outlet ID
• VV = voltage: [120,240,480,277] mapped to [0,1,2,3]
• RRR = current rating: [20,30,50,60,15] mapped to [1,2,4,5,7]
• G = flag set if there's no ground

For instance, the outlet 10-30 is encoded as 0xD5 = 0b11010101:

11 01 010 1
|  |   | |
|  |   | +--> no ground
|  |   +----> rating 2 (30A)
|  +--------> voltage 1 (240V)
+-----------> previous ID + 3 (7 + 3 = 10)


The whole data is stored as a single string of two-nibble hexadecimal values, which are split with a match().

### Decoding

The leading ID is updated with:

n += x >> 6


Because $$\277\$$ is $$\960\bmod683\$$, the voltage is decoded with:

V = (120 << x / 16 % 4) % 683


Because $$\15\$$ is $$\80\bmod65\$$, the current rating is decoded with:

R = -~(x / 2 & 7) * 10 % 65

• I don't know how this works, but I am in awe... – A username Mar 27 at 10:17
• @Ausername I've added an explanation. – Arnauld Mar 27 at 10:33

# Charcoal, 115 bytes

≔¹⁰⁰εＮθＮηＮζＩＥΦＩ⪪”)⧴→ＷuJＳN4⊘Ｒf⎚θ⊕∧H,\m↖⊗？Yς×≧üλθ▷TE⦄→×◧Àλ≧”⁴¬∨›ζ‹⁵﹪÷ιε⁸∨›η﹪ιε‹·¹↔⁻¹∕θ⎇⁼⁷÷ιε²⁷⁷×¹²⁰⎇⁼¹¹÷ιε²⊕﹪⊖÷ιε⁴↨ιε


Try it online! Link is to verbose version of code. Takes the groundedness as an integer, 1 = grounded, 0 = ungrounded and outputs in array format [[N, nn], ...] (string format is possible at the cost of 1 byte). Explanation:

≔¹⁰⁰ε


Save the value 100 as it gets used a lot. (Charcoal only has predefined variables for 10 and 1000.)

ＮθＮηＮζ


Input the voltage, current and groundedness.

ＩＥΦＩ⪪”)⧴→ＷuJＳN4⊘Ｒf⎚θ⊕∧H,\m↖⊗？Yς×≧üλθ▷TE⦄→×◧Àλ≧”⁴¬


Split the compressed string of outlets in NNnn format into individual outlets in decimal, and filter out any that fail any of the following tests:

∨›ζ‹⁵﹪÷ιε⁸


The device needs to be grounded, but NN (modulo 8) is less than 5.

∨›η﹪ιε


The device requires more than nn current.

‹·¹↔⁻¹∕θ⎇⁼⁷÷ιε²⁷⁷×¹²⁰⎇⁼¹¹÷ιε²⊕﹪⊖÷ιε⁴


Dividing the device's voltage by the receptacle's voltage results in a value outside the range 0.9..1.1. The receptacle's voltage is calculated as NN (modulo 4, or 4 if NN is a multiple of 4, or 2 if NN is 11) multiplied by 120, unless NN is 7, in which case 277 is used instead.

↨ιε


Split the NNnn integer into separate NN and nn values by converting into base 100.

# Ruby, 155 150 bytes

f=->v,a,g{z=0
"yQxwxwTxwuUuuwubvuw	 xwu".bytes{|i|z+=121-i
(v-q=(16<<z/140)*7.5%683)**2<=q*q/100&&g*4<=(t=z/10%14)%8&&a<=(c=z%10*5+15)&&(p [t+1,c])}}


Try it online!

The magic string contains one character 14 and one tab (character 9).

A function taking 3 inputs: volts, amps, ground (where ground is 0 or 1.)

Prints a list of two-element arrays to stdout. These are ordered by rated voltage, so the ordering of the output may differ a little from the test cases in the question, but they are all there.

Commented code

f=->v,a,g{z=0                         #Input voltage, current and grounding. Set z=0
"yQxwxwTxwuUuuwubvuw     xwu".        #Magic string, one byte per outlet spec.
bytes{|i|z+=121-i                #Iterate through bytes and increment z.
(v-q=(16<<z/140)*7.5%683)**2<=   #16*7.5=120V. rightshift by z/140 to get 240, 480 or 960%683=277V. Find the difference from input and square it.
q*q/100&&                        #If the difference is 1/10 of the outlet rating or less... (NB. q/10 must be squared to compare with the above)
g*4<=(t=z/10%14)%8&&           #Extract the outlet type (minus 1.) Grounded outlets have t%8 greater or equal to 4. If grounding acceptable....
a<=(c=z%10*5+15)&&           #Decode the current rating. If acceptable...
(p [t+1,c])}               #Print the outlet spec: type and current rating.
}


I decided to order by voltage rating as there are only 4 possible values, hence only 3 steps in voltage, only 2 of which result in nonprintable characters in the magic string.

Realising that subtracting 1 from the outlet type and taking modulo 8 always gives a number of 4 or greater for grounded outlets and never for ungrounded ones was handy as I didn't have to compress this.

# JavaScript (Node.js), 310 294 bytes

(x,y,z)=>[...'demuhpaiqybjrzu}mu}oaqyY'].map((x,i)=>[[120,240,277,480][(s=x.charCodeAt())%4],h=[12,3,4,6,10][(s-s%8)/8-11]*5,(s-s%4)/4%2,[[...'11000300100010003010012000'].map(x=>+x).slice(0,i+2).reduce((a,b)=>a+b),h]]).filter(m=>9*m[0]/10<=x&&11*m[0]/10>=x&&y<=m[1]&&(z?!m[2]:1)).map(x=>x[3])


Arnauld beat me to this, and did it better, but I put two hours of work into this...

The string compression is interesting. Above, each character in

demuhpaiqybjrzu}mu}oaqyY
is the binary data for:


d
To char code is 100
To binary is 1100100

1 - just on the start
100 - Represents current 15 - 100 => 15, 101 => 20, 110 => 30, 111 => 50, 011 => 60
1 - No ground (0 for ground)
00 - Voltage 120 - 00 => 120, 01 => 240, 10 => 277, 11 => 480.


And in this way each outlet is encoded into a single character.

## Explanation

(x,y,z)=>                                        // declare function
[...'demuhpaiqybjrzu}mu}oaqyY']                 // see above on compression
.map((x,i)=>                                     //map by item / index
[                                                //return array of:
[120,240,277,480]                                // possible voltages
[(s=x.charCodeAt())%4],                          //decipher from string & get correct value
h=                                               //save following for use in name
[12,3,4,6,10]                                    //possible current values,
[(s-s%8)/8-8]*5,                                 //get correct one from decoded string item and multiply by 5
(s-s%4)/4%2,                                     // get ground boolean
[[...'11000300100010003010012000']               // change in first part of string each time - sum of first m will be first part of name m
.map(x=>+x)                                      // to array of numbers
.slice(0,i+2).reduce((a,b)=>a+b)                 //sum of first [index]
,h]                                              // + '-' + h, the current value we saved earlier, produces name
])
//This is where all the magic happens, up to here is just data compression
.filter(m=>                                      //filter m by if all are true:
9*m[0]/10<=x                                     //9/10 of m[0] (voltage) is less than given voltage
&&11*m[0]/10>=x                                  // 11/10 of m[0] (voltage) is greater than given voltage (so voltage is within 10%)
&&y<=m[1]                                        // given current is less than or equal to m[1] (current)
&&(z?                                            //if breaker required
!m[2]                                            //check if breaker
:1)                                              //else always true
).map(x=>x[3])                                   // convert to list of names


# Excel, 220 bytes

135 bytes for this formula.

=LET(f,B1:J1*B2:J6,r,A2:A6,v,XLOOKUP(f,L1:L4,M1:M4,240),TEXTJOIN(",",,IF((ABS(A8-v)<=v/10)*(B8<=r)*((MOD(f,10)>3)+1-C8)*f,f&"-"&r,"")))


68 bytes for this array of cells that shows the valid pairs of numbers before and after the dash.

    1   2   5   6   7   10  11  12  14
15  1   1   1   1   1   0   0   0   0
20  0   1   1   1   1   0   1   1   1
30  0   1   1   1   1   1   1   0   1
50  0   0   0   1   1   1   1   0   1
60  0   0   0   0   0   0   0   0   1


17 byte for this array of cells that maps the numbers before the dash to voltages other than 240.

 1 120
5 120
7 277
12 480
`