14
\$\begingroup\$

Given an atomic number in the inclusive range [1,118], write the shortest program/function that outputs one of {2,8,18} if the element with that atomic number follows the duplet, octet, or 18-electron rule, respectively.

Notes

  • The Octet/Duplet/18-electron rule is a rule of thumb that describes how many electrons is needed for an element to completely fill their outer electron shells.
  • The Duplet rule only applies to H, He, and Li (atomic numbers 1, 2, and 3)
  • The 18-electron rule applies to all transition metals (21-30, 39-48, 72-80, 104-112), lanthanides (57-71), and actinides (89-103).
  • The Octet rule applies to everything else (4-20, 31-38, 49-56, 81-88, 113-118).

Test Cases

input => output
1 => 2
2 => 2
3 => 2
4 => 8
18 => 8
19 => 8
20 => 8
21 => 18
26 => 18
30 => 18
31 => 8
92 => 18
118 => 8
\$\endgroup\$
4
  • \$\begingroup\$ Similar: Electron Configurations, Electron Configuration \$\endgroup\$
    – bigyihsuan
    Commented Feb 10, 2023 at 16:26
  • \$\begingroup\$ I think there's a typo - it says the Octet rule applies to "133-118", it should be "113-118" \$\endgroup\$
    – The Thonnu
    Commented Feb 10, 2023 at 17:39
  • 1
    \$\begingroup\$ @TheThonnu fixed \$\endgroup\$
    – bigyihsuan
    Commented Feb 10, 2023 at 17:40
  • \$\begingroup\$ As a former chemistry major, I'd like to point out that the "octet" elements are those of the last 6 columns of the periodic table, wrapping round to the first 2 columns, to form runs of 8 elements. Element 4 Beryllium would then fit as a duplet, but in reality Be2+ in water borrows back 8 electrons from H2O to form Be(4*H2O)2+ to become like neon, so Wikipedia calls it an additional octet element. As for the other elements being 18-electron: the actual situation with lanthanides and actinides is way more complex but changing the rules of the question at this stage will render answers invalid \$\endgroup\$ Commented Feb 10, 2023 at 21:28

11 Answers 11

5
\$\begingroup\$

Excel, 60 bytes

=IFNA(8+10*ISEVEN(MATCH(A1,{4,21,31,39,49,57,81,89,113})),2)

Input in cell A1.

\$\endgroup\$
0
5
\$\begingroup\$

Charcoal, 22 bytes

I⊗§”|↖⁵Z·⁰χ⦄P↑mMρbl∨”N

Try it online! Link is to verbose version of code. Explanation: Most of the program is simply a compressed look-up table.

   ”...”    Compressed look-up table
  §         Indexed by
        N   Input as a number
 ⊗          Doubled
I           Cast to string
            Implicitly print
\$\endgroup\$
5
\$\begingroup\$

Vyxal, 19 18 bytes

»µ7!¾∷»₄τ¦>ḣ∑∷+›²d

Try it Online! or verify all test cases.

-1 byte by porting part of Jonathan Allan's Jelly answer.

»...»               # push compressed integer
     ₄τ             # convert to base 26
       ¦            # cumulative sum
                        this results in the list [3,20,30,38,48,56,80,88,112]
        >           # is less than input?
         ḣ          # extract head, pushes a[0] and a[1:] (a[0] == 0 iff input is less than 4)
          ∑         # sum
           ∷        # modulo 2 (this is 1 iff the 18-electron rule applies)
            +       # add
             ›      # increment
              ²     # square
               d    # double
\$\endgroup\$
4
\$\begingroup\$

Ruby, 42 bytes

->m{m>3?8+5*(2&70352637804063<<-m/2+12):2}

Try it online!

Unfortunately this fairly unimaginative approach works best.

Ruby rounds toward -infinity, so the minus sign in -m/2 ensures that transitions occur in the right place. This expression evaluates to -10 for both 19 and 20 input, and -11 for both 21 and 22 input. To get the first 18 output, we take this -11 and add 12 for an overall shift of +1. This gives a final answer of 8+5*(2) which is 18. Larger numbers give negative leftshift, which Ruby interprets as positive rightshift.

the magic number can be replaced by 0x3ffc3ffc3e1f which is the same number of bytes. If three leading zeroes are added to the hex number, +12 can be deleted, but it's the same number of bytes.

Ruby, 65 bytes

->m{n=0
" $(1:JZ".bytes{|i|n+=15<<i}
m>3?18-10*(1&n>>(m+67)/2):2}

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Your 54-byte solution is actually 44 since it contains 10 trailing spaces... \$\endgroup\$ Commented Feb 11, 2023 at 1:51
  • \$\begingroup\$ @dingledooper thanks. It's 42 bytes now. \$\endgroup\$ Commented Feb 11, 2023 at 2:22
4
\$\begingroup\$

Jelly, 19 bytes

>“Þœ&08PXp“¤‘§ḂS‘²Ḥ

A monadic Link that accepts an integer from \$[1,118]\$ and yields the rule, \$2\$, \$8\$, or \$18\$.

Try it online!

How?

>“...“¤‘§ḂS‘²Ḥ - Link: Atomic number, A   e.g. 48
 “...“¤‘       - lists of code-page indices -> [[20,30,38,48,56,80,88,112],[3]]
>              - (A) greater than? (that)      [[ 1, 1, 1, 0, 0, 0, 0,  0],[1]]
        §      - sums                          [3,1]
         Ḃ     - mod two                       [1,1]
          S    - sum                           2
           ‘   - increment                     3
            ²  - square                        9
             Ḥ - double                        18
\$\endgroup\$
4
\$\begingroup\$

Python, 72 71 56 55 bytes

lambda n:(n<4or sum(i>n for i in b"\x04\x15\x1f'19QYq")%2*5+4)*2

Attempt This Online!

(But the \x04\x15\x1f should be replaced with the actual unprintable characters)

Based off Jos Woolley's Excel answer.

-15 thanks to dingledooper
-1 thanks to pan

Python, 66 bytes

lambda n:(n<4)*2+((20<n<31)+(38<n<49)+(56<n<81)+(88<n<113))*18or 8

Attempt This Online!

\$\endgroup\$
3
  • \$\begingroup\$ In the second answer, you can save a bunch by using a byte string instead of an array. \$\endgroup\$ Commented Feb 10, 2023 at 20:00
  • \$\begingroup\$ @dingledooper thanks! I didn't think of that. \$\endgroup\$
    – The Thonnu
    Commented Feb 10, 2023 at 20:11
  • \$\begingroup\$ 55 \$\endgroup\$
    – pan
    Commented Feb 18, 2023 at 4:38
3
\$\begingroup\$

05AB1E, 20 bytes

49Þ1š•N‚Ÿи––•₂вÅΓ·Iè

Port of @Neil's Charcoal answer.

Try it online or verify all test cases.

A port of @AndrovT's Vyxal answer is 20 bytes as well:

•¶sWü„•₂вηO›ćsOÉ6«*Ì

Try it online or verify all test cases.

Make sure to upvote both @Neil's and @AndrovT's answers as well!

Explanation:

49              # Push 49
  Þ             # Cycle it indefinitely: [4,9,4,9,4,9,...]
   1š           # Prepend a 1: [1,4,9,4,9,4,9,...]
     •N‚Ÿи––•   # Push compressed integer 25350987139094
       ₂в       # Convert it to base-26 as list: [4,17,10,8,10,8,24,8,24,6]
         ÅΓ     # Run-length decode the two lists: [1,1,1,1,4,4,4,...]
           ·    # Double each: [2,2,2,2,8,8,8,...]
            Iè  # (0-based) index the input into it
                # (after which the result is output implicitly)

•¶sWü„•         # Push compressed integer 766210902312
  ₂в            # Convert it to base-26 as list: [3,17,10,8,10,8,24,8,24]
    η           # Get all prefixed of this list: [[3],[3,17],[3,17,10],...]
     O          # Sum each inner prefix: [3,20,30,38,48,56,80,88,112]
      ›         # Check if the (implicit) input-integer is larger than the values
       ć        # Extract head; push first item and remainder-list separately
        s       # Swap so the remainder-list is at the top of the stack
         O      # Sum it
          É     # Modulo-2 (with an is_odd check)
           6«   # Append a 6 to this 0 or 1
             *  # Multiply it to the extracted head
              Ì # Increase it by 2
                # (after which the result is output implicitly)

See this 05AB1E tip of mine (sections How to compress large integers? and How to compress integer lists?) to understand why •N‚Ÿи––• is 25350987139094; •N‚Ÿи––•₂в is [4,17,10,8,10,8,24,8,24,6]; •¶sWü„• is 766210902312; and •¶sWü„•₂в is [3,17,10,8,10,8,24,8,24].

\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES6), 42 bytes

A hash formula with a 32-bit lookup.

n=>n<4?2:60620415>>(-~n>>1)*223%511&1?18:8

Try it online!


JavaScript (ES6), 47 bytes

A longer but slightly more subtle method.

n=>n<4?2:--n%16>="_468080"[n>>4]^n>29&n<32?18:8

Try it online!

Method

This is based on the pattern that appears when the atomic numbers are arranged by groups of \$16\$, starting at \$0\$ instead of \$1\$. We use the following condition to determine whether it's 18-electon or octet:

$$(n \bmod 16)\ge T_{\lfloor n/16 \rfloor}$$

There's unfortunately an exception for \$n=30\$ and \$n=31\$ (atomic numbers \$31\$ and \$32\$) which is not golfed very efficiently, making this method overall less competitive than the one using a more basic hash.

In the diagram below, we use +, . and x for duplet, octet and 18-electron respectively.

   | 0 1 2 3 4 5 6 7 8 9 A B C D E F
---+--------------------------------
00 | + + + . . . . . . . . . . . . .
10 | . . . . x x x x x x x x x x . .
20 | . . . . . . x x x x x x x x x x
30 | . . . . . . . . x x x x x x x x
40 | x x x x x x x x x x x x x x x x
50 | . . . . . . . . x x x x x x x x
60 | x x x x x x x x x x x x x x x x
70 | . . . . . . 
\$\endgroup\$
0
2
\$\begingroup\$

C (GCC), 81 76 71 68 57 bytes

thanks neil for -11 bytes

f(x){x=x<4?2:0x1fffffe01fffffe01ff807fell<<20>>x&1?18:8;}

Attempt This Online!

Return 2 for <= 3, otherwise lookup the value in the 64-bit constants, where 0 is the 18 rule and 1 is the 8 rule.

\$\endgroup\$
1
  • \$\begingroup\$ Save 11 bytes by using a 128-bit integer constant: f(x){x=x<4?2:0x1fffffe01fffffe01ff807fell<<20>>x&1?18:8;} \$\endgroup\$
    – Neil
    Commented Feb 10, 2023 at 22:55
2
\$\begingroup\$

Pip, 61 47 41 bytes

Ia<4P2EL{P%#({\a>a}FI(A*"&08PXp"))*t+8}

Attempt This Online!

-20 thanks to @DLosc

Explanation

Ia<4        # if the input is less than 4:
    P2      #  print 2
      EL{   # else:
P           #  print the following:
 %#(        #   length mod 2 of:
    {\a>a}  #    is the input greater than this number?
FI(A*"...") #    filter the list [20,30,38,48,56,80,88,112] by the above
)*t+8       #   times 10 plus 8 
     }      # enf if

Old:

Ia<4        # if the input is less than 4:
    P2      #  print 2
      EL{   # else:
Fi       {  #  for i in ...
  A*"..."   #  the ASCII code points of the string
            #     [20,30,38,48,56,80,88,112]:
l:lAE       #   append the following to l
     (a>i)  #   is the input greater than i?
          } #  end for
P           #  print ...
  (1Nl)     #  ... the count of 1s in l ...
 %          #  ... mod 2 ...
*t+8        #  ... times 10 plus 8
     }      # end if
\$\endgroup\$
2
  • \$\begingroup\$ Probably the shortest way to generate the list [20;30;38;48;56;80;88;112], if you don't mind a couple of unprintable characters, is to make an 8-character string with those codepoints and use A* to get the ASCII code of each character: ATO. l:lAE(a>i) can be lAE:a>i, but in this case I'd suggest instead filtering the list and taking the length of the result. Also, several of the curly braces and parentheses are unnecessary; try removing them one pair at a time and see if you get the same results. \$\endgroup\$
    – DLosc
    Commented Feb 17, 2023 at 23:06
  • \$\begingroup\$ Oh, and t is initialized to 10, so that'll save a byte. \$\endgroup\$
    – DLosc
    Commented Feb 17, 2023 at 23:08
1
\$\begingroup\$

Scala, 103 bytes

Modified from @The Thonnu's answer.


Golfed version. Try it online!

def f(n:Int)=if(n<4)2 else(Seq[Byte](0x04,0x15,0x1f,0x27,0x31,0x39,0x51,0x59,0x71).count(_ >n)%2*5+4)*2

Ungolfed version.

object PythonToScala {
  def f(n: Int): Int = {
    val b = Array[Byte](0x04, 0x15, 0x1f, 0x27, 0x31, 0x39, 0x51, 0x59, 0x71)
    if (n < 4) 2
    else (b.count(_ > n) % 2 * 5 + 4) * 2
  }

  def main(args: Array[String]): Unit = {
    for (i <- 1 to 118) {
      println(s"$i  \t-->\t  ${f(i)}")
    }
  }
}

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.