Enable Javascript in your browser and then refresh this page, for a much enhanced experience.
veky's version, modified solution in Clear category for Periodic Table by Phil15
# veky's version, modified
from collections import Counter
from functools import partial
from typing import Callable, List, NamedTuple, Tuple
TABLE = '''
H He
Li Be B C N O F Ne
Na Mg Al Si P S Cl Ar
K Ca Sc Ti V Cr Mn Fe Co Ni Cu Zn Ga Ge As Se Br Kr
Rb Sr Y Zr Nb Mo Tc Ru Rh Pd Ag Cd In Sn Sb Te I Xe
Cs Ba %s Hf Ta W Re Os Ir Pt Au Hg Tl Pb Bi Po At Rn
Fr Ra %s Rf Db Sg Bh Hs Mt Ds Rg Cn Uut Fl Uup Lv Uus Uuo
''' % (
'La Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu',
'Ac Th Pa U Np Pu Am Cm Bk Cf Es Fm Md No Lr',
)
SYMBOLS = TABLE.split()
DIGITS = str.maketrans('0123456789', '⁰¹²³⁴⁵⁶⁷⁸⁹')
class Level(NamedTuple):
shell: int
orbital: int
@property
def full(self) -> int:
return 4 * self.orbital + 2
def no_orbital(self) -> bool:
return not self.orbital
ORBS = [
Level(shell - orbital, orbital)
for shell in range(9)
for orbital in range(9)[::-1]
if shell - orbital > orbital
]
LEVELS = [level for level in ORBS for _ in range(level.full)]
EXCEPTIONS = {
24: [5],
29: [5],
41: [8],
42: [8],
44: [8],
45: [8],
46: [8, 8],
47: [8],
57: [12],
58: [12],
64: [12],
78: [11, 12],
79: [11, 12],
89: [16],
90: [16, 16],
91: [16],
92: [16],
93: [16],
96: [16],
103: [17],
}
def layout(electrons: Callable[[Level, int], str], orbs: List[Level], counts: Counter) -> str:
return ' '.join(electrons(orb, counts[orb]) for orb in orbs if counts[orb])
def fill(level: Level, n: int) -> str:
half = level.full // 2
q, r = divmod(n, half)
return str(q + 1) * r + str(q) * (half - r)
def condensed(level: Level, n: int) -> str:
return str(level.shell) + 'spdf'[level.orbital] + str(n).translate(DIGITS)
configuration_notation = partial(layout, condensed, sorted(ORBS))
orbital_model = partial(layout, fill, ORBS)
def electron_classifier(atomic_number: int) -> Counter:
return Counter(LEVELS[:atomic_number])
def checkio(symbol: str) -> Tuple[str, str, str]:
atomic_number = SYMBOLS.index(symbol) + 1
counts = electron_classifier(atomic_number)
noble = LEVELS.index(max(filter(Level.no_orbital, counts)))
for orbital in EXCEPTIONS.get(atomic_number, []):
# hop 1 election to the next orbital
counts[ORBS[orbital]] -= 1
counts[ORBS[orbital + 1]] += 1
conf = configuration_notation(counts - electron_classifier(noble))
if noble:
conf = f'[{SYMBOLS[noble - 1]}] {conf}'
return str(atomic_number), conf, orbital_model(counts)
if __name__ == '__main__':
TESTS = [
(
'H',
('1', '1s¹', '1'),
'First - 1s¹',
),
(
'He',
('2', '1s²', '2'),
'Second - 1s²',
),
(
'Al',
('13', '[Ne] 3s² 3p¹', '2 2 222 2 100'),
'Third - 1s² 2s² 2p⁶ 3s² 3p¹',
),
(
'O',
('8', '[He] 2s² 2p⁴', '2 2 211'),
'Fourth - 1s² 2s² 2p⁴',
),
(
'Li',
('3', '[He] 2s¹', '2 1'),
'Fifth - 1s² 2s¹',
),
(
'Uuo',
(
'118',
'[Rn] 5f¹⁴ 6d¹⁰ 7s² 7p⁶',
'2 2 222 2 222 2 22222 222 2 22222 222 2 2222222 22222 222 2 '
'2222222 22222 222',
),
'Ununoctium',
),
(
'Cr',
(
'24',
'[Ar] 3d⁵ 4s¹',
'2 2 222 2 222 1 11111',
),
'Chromium',
),
(
'In',
(
'49',
'[Kr] 4d¹⁰ 5s² 5p¹',
'2 2 222 2 222 2 22222 222 2 22222 100',
),
'Indium',
),
(
'I',
(
'53',
'[Kr] 4d¹⁰ 5s² 5p⁵',
'2 2 222 2 222 2 22222 222 2 22222 221',
),
'Iodine',
),
(
'Ir',
(
'77',
'[Xe] 4f¹⁴ 5d⁷ 6s²',
'2 2 222 2 222 2 22222 222 2 22222 222 2 2222222 22111',
),
'Iridium',
),
(
'Tl',
(
'81',
'[Xe] 4f¹⁴ 5d¹⁰ 6s² 6p¹',
'2 2 222 2 222 2 22222 222 2 22222 222 2 2222222 22222 100',
),
'Thallium',
),
(
'Db',
(
'105',
'[Rn] 5f¹⁴ 6d³ 7s²',
'2 2 222 2 222 2 22222 222 2 22222 222 2 2222222 22222 222 2 '
'2222222 11100',
),
'Dubnium',
),
(
'V',
('23', '[Ar] 3d³ 4s²', '2 2 222 2 222 2 11100'),
'Vanadium',
),
(
'Rn',
(
'86',
'[Xe] 4f¹⁴ 5d¹⁰ 6s² 6p⁶',
'2 2 222 2 222 2 22222 222 2 22222 222 2 2222222 22222 222',
),
'Radon',
),
(
'Xe',
(
'54',
'[Kr] 4d¹⁰ 5s² 5p⁶',
'2 2 222 2 222 2 22222 222 2 22222 222',
),
'Radon',
),
(
'Br',
('35', '[Ar] 3d¹⁰ 4s² 4p⁵', '2 2 222 2 222 2 22222 221'),
'Bromine',
),
(
'Na',
('11', '[Ne] 3s¹', '2 2 222 1'),
None,
),
(
'Kr',
('36', '[Ar] 3d¹⁰ 4s² 4p⁶', '2 2 222 2 222 2 22222 222'),
None,
),
(
'K',
('19', '[Ar] 4s¹', '2 2 222 2 222 1'),
None,
),
(
'Cu',
('29', '[Ar] 3d¹⁰ 4s¹', '2 2 222 2 222 1 22222'),
None,
),
(
'Ds',
(
'110',
'[Rn] 5f¹⁴ 6d⁸ 7s²',
'2 2 222 2 222 2 22222 222 2 22222 222 2 2222222 22222 222 2 '
'2222222 22211',
),
None,
),
(
'Ar',
('18', '[Ne] 3s² 3p⁶', '2 2 222 2 222'),
None,
),
(
'Rb',
('37', '[Kr] 5s¹', '2 2 222 2 222 2 22222 222 1'),
None,
),
(
'Uus',
(
'117',
'[Rn] 5f¹⁴ 6d¹⁰ 7s² 7p⁵',
'2 2 222 2 222 2 22222 222 2 22222 222 2 2222222 22222 222 2 '
'2222222 22222 221',
),
None,
),
(
'Cl',
('17', '[Ne] 3s² 3p⁵', '2 2 222 2 221'),
None,
),
(
'Fr',
(
'87',
'[Rn] 7s¹',
'2 2 222 2 222 2 22222 222 2 22222 222 2 2222222 22222 222 1',
),
None,
),
]
for element, answer, explanation in TESTS:
assert checkio(element) == answer, explanation
March 10, 2022