Periodic table
Display the row and column in the periodic table of the given atomic number.
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
- The periodic table
Let us consider the following periodic table representation.
__________________________________________________________________________ | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | | | |1 H He | | | |2 Li Be B C N O F Ne | | | |3 Na Mg Al Si P S Cl Ar | | | |4 K Ca Sc Ti V Cr Mn Fe Co Ni Cu Zn Ga Ge As Se Br Kr | | | |5 Rb Sr Y Zr Nb Mo Tc Ru Rh Pd Ag Cd In Sn Sb Te I Xe | | | |6 Cs Ba * Hf Ta W Re Os Ir Pt Au Hg Tl Pb Bi Po At Rn | | | |7 Fr Ra ° Rf Db Sg Bh Hs Mt Ds Rg Cn Nh Fl Mc Lv Ts Og | |__________________________________________________________________________| | | | | |8 Lantanoidi* La Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu | | | |9 Aktinoidi° Ak Th Pa U Np Pu Am Cm Bk Cf Es Fm Md No Lr | |__________________________________________________________________________|
- Example test cases;
-
1
->1 1
-
2
->1 18
-
29
->4 11
-
42
->5 6
-
57
->8 4
-
58
->8 5
-
72
->6 4
-
89
->9 4
- Details;
The representation of the periodic table may be represented in various way. The one presented in this challenge does have the following property : Lantanides and Aktinoides are all in a dedicated row, hence there is no element that is placed at 6, 3 nor 7, 3.
You may take a look at the atomic number repartitions here.
The atomic number is at least 1, at most 118.
- See also
- the periodic table
- This task was an idea from CompSciFact
- The periodic table in ascii that was used as template
ALGOL 68
<lang algol68>BEGIN # display the period and group number of an element, #
# given its atomic number # INT max atomic number = 118; # highest known element # # the positions are stored as: # # ( group number * group multiplier ) + period # INT group multiplier = 100; [ 1 : max atomic number ]INT position; # construct the positions of the elements in the table # BEGIN STRING periodic table = "- =" + "-- -----=" + "-- -----=" + "-----------------=" + "-----------------=" + "--8--------------=" + "--9--------------=" ; INT period := 1; INT group := 1; INT element := 1; FOR t FROM LWB periodic table TO UPB periodic table DO CHAR p = periodic table[ t ]; IF p = "8" OR p = "9" THEN # lantanoids or actinoids # INT series period = IF p = "8" THEN 8 ELSE 9 FI; INT series group := 4; FOR e TO 15 DO position[ element ] := ( group multiplier * series group ) + series period; element +:= 1; series group +:= 1 OD ELIF p /= " " THEN # there is a single element here # position[ element ] := ( group multiplier * group ) + period; element +:= 1; IF p = "=" THEN # final element of the period # period +:= 1; group := 0 FI FI; group +:= 1 OD END; # display the period and group numbers of test elements # []INT test = ( 1, 2, 29, 42, 57, 58, 59, 71, 72, 89, 90, 103, 113 ); FOR t FROM LWB test TO UPB test DO INT e = test[ t ]; IF e < LWB position OR e > UPB position THEN print( ( "Invalid element: ", whole( e, 0 ), newline ) ) ELSE INT period = position[ e ] MOD group multiplier; INT group = position[ e ] OVER group multiplier; print( ( "Element ", whole( e, -3 ) , " -> ", whole( period, 0 ), ", ", whole( group, -2 ) , newline ) ) FI OD
END</lang>
- Output:
Element 1 -> 1, 1 Element 2 -> 1, 18 Element 29 -> 4, 11 Element 42 -> 5, 6 Element 57 -> 8, 4 Element 58 -> 8, 5 Element 59 -> 8, 6 Element 71 -> 8, 18 Element 72 -> 6, 4 Element 89 -> 9, 4 Element 90 -> 9, 5 Element 103 -> 9, 18 Element 113 -> 7, 13
Go
<lang ecmascript>package main
import (
"fmt" "log"
)
var limits = [][2]int{
{3, 10}, {11, 18}, {19, 36}, {37, 54}, {55, 86}, {87, 118},
}
func periodicTable(n int) (int, int) {
if n < 1 || n > 118 { log.Fatal("Atomic number is out of range.") } if n == 1 { return 1, 1 } if n == 2 { return 1, 18 } if n >= 57 && n <= 71 { return 8, n - 53 } if n >= 89 && n <= 103 { return 9, n - 85 } var row, start, end int for i := 0; i < len(limits); i++ { limit := limits[i] if n >= limit[0] && n <= limit[1] { row, start, end = i+2, limit[0], limit[1] break } } if n < start+2 || row == 4 || row == 5 { return row, n - start + 1 } return row, n - end + 18
}
func main() {
for _, n := range []int{1, 2, 29, 42, 57, 58, 59, 71, 72, 89, 90, 103, 113} { row, col := periodicTable(n) fmt.Printf("Atomic number %3d -> %d, %-2d\n", n, row, col) }
}</lang>
- Output:
Atomic number 1 -> 1, 1 Atomic number 2 -> 1, 18 Atomic number 29 -> 4, 11 Atomic number 42 -> 5, 6 Atomic number 57 -> 8, 4 Atomic number 58 -> 8, 5 Atomic number 59 -> 8, 6 Atomic number 71 -> 8, 18 Atomic number 72 -> 6, 4 Atomic number 89 -> 9, 4 Atomic number 90 -> 9, 5 Atomic number 103 -> 9, 18 Atomic number 113 -> 7, 13
Julia
<lang ruby>const limits = [3:10, 11:18, 19:36, 37:54, 55:86, 87:118]
function periodic_table(n)
(n < 1 || n > 118) && error("Atomic number is out of range.") n == 1 && return [1, 1] n == 2 && return [1, 18] 57 <= n <= 71 && return [8, n - 53] 89 <= n <= 103 && return [9, n - 85] row, limitstart, limitstop = 0, 0, 0 for i in eachindex(limits) if limits[i].start <= n <= limits[i].stop row, limitstart, limitstop = i + 1, limits[i].start, limits[i].stop break end end return (n < limitstart + 2 || row == 4 || row == 5) ? [row, n - limitstart + 1] : [row, n - limitstop + 18]
end
for n in [1, 2, 29, 42, 57, 58, 59, 71, 72, 89, 90, 103, 113]
rc = periodic_table(n) println("Atomic number ", lpad(n, 3), " -> ($(rc[1]), $(rc[2]))")
end
</lang>
- Output:
Atomic number 1 -> (1, 1) Atomic number 2 -> (1, 18) Atomic number 29 -> (4, 11) Atomic number 42 -> (5, 6) Atomic number 57 -> (8, 4) Atomic number 58 -> (8, 5) Atomic number 59 -> (8, 6) Atomic number 71 -> (8, 18) Atomic number 72 -> (6, 4) Atomic number 89 -> (9, 4) Atomic number 90 -> (9, 5) Atomic number 103 -> (9, 18) Atomic number 113 -> (7, 13)
Perl
<lang perl>use strict; use warnings; no warnings 'uninitialized'; use feature 'say'; use List::Util <sum head>;
sub divmod { int $_[0]/$_[1], $_[0]%$_[1] }
my $b = 18; my(@offset,@span,$cnt); push @span, ($cnt++) x $_ for <1 3 8 44 15 17 15 15>; @offset = (16, 10, 10, (2*$b)+1, (-2*$b)-15, (2*$b)+1, (-2*$b)-15);
for my $n (<1 2 29 42 57 58 72 89 90 103 118>) {
printf "%3d: %2d, %2d\n", $n, map { $_+1 } divmod $n-1 + sum(head $span[$n-1], @offset), $b;
}</lang>
- Output:
1: 1, 1 2: 1, 18 29: 4, 11 42: 5, 6 57: 8, 4 58: 8, 5 72: 6, 4 89: 9, 4 90: 9, 5 103: 9, 18
Phix
with javascript_semantics constant match_wp = false function prc(integer n) constant t = {0,2,10,18,36,54,86,118,119} integer row = abs(binary_search(n,t,true))-1, col = n-t[row] if col>1+(row>1) then col = 18-(t[row+1]-n) if match_wp then if col<=2 then return {row+2,col+14} end if else -- matches above ascii: if col<=2+(row>5) then return {row+2,col+15} end if end if end if return {row,col} end function sequence pt = repeat(repeat(" ",19),10) pt[1][2..$] = apply(true,sprintf,{{"%3d"},tagset(18)}) -- column headings for i=1 to 9 do pt[i+1][1] = sprintf("%3d",i) end for -- row numbers for i=1 to 118 do integer {r,c} = prc(i) pt[r+1][c+1] = sprintf("%3d",i) end for if not match_wp then -- (ascii only:) pt[7][4] = " L*" pt[8][4] = " A*" pt[9][2..4] = {"Lanthanide:"} pt[10][2..4] = {" Actinide:"} end if printf(1,"%s\n",{join(apply(true,join,{pt,{"|"}}),"\n")})
- Output:
With match_wp set to true:
| 1| 2| 3| 4| 5| 6| 7| 8| 9| 10| 11| 12| 13| 14| 15| 16| 17| 18 1| 1| | | | | | | | | | | | | | | | | 2 2| 3| 4| | | | | | | | | | | 5| 6| 7| 8| 9| 10 3| 11| 12| | | | | | | | | | | 13| 14| 15| 16| 17| 18 4| 19| 20| 21| 22| 23| 24| 25| 26| 27| 28| 29| 30| 31| 32| 33| 34| 35| 36 5| 37| 38| 39| 40| 41| 42| 43| 44| 45| 46| 47| 48| 49| 50| 51| 52| 53| 54 6| 55| 56| 71| 72| 73| 74| 75| 76| 77| 78| 79| 80| 81| 82| 83| 84| 85| 86 7| 87| 88|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118 8| | | 57| 58| 59| 60| 61| 62| 63| 64| 65| 66| 67| 68| 69| 70| | 9| | | 89| 90| 91| 92| 93| 94| 95| 96| 97| 98| 99|100|101|102| |
Or with match_wp false:
| 1| 2| 3| 4| 5| 6| 7| 8| 9| 10| 11| 12| 13| 14| 15| 16| 17| 18 1| 1| | | | | | | | | | | | | | | | | 2 2| 3| 4| | | | | | | | | | | 5| 6| 7| 8| 9| 10 3| 11| 12| | | | | | | | | | | 13| 14| 15| 16| 17| 18 4| 19| 20| 21| 22| 23| 24| 25| 26| 27| 28| 29| 30| 31| 32| 33| 34| 35| 36 5| 37| 38| 39| 40| 41| 42| 43| 44| 45| 46| 47| 48| 49| 50| 51| 52| 53| 54 6| 55| 56| L*| 72| 73| 74| 75| 76| 77| 78| 79| 80| 81| 82| 83| 84| 85| 86 7| 87| 88| A*|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118 8|Lanthanide:| 57| 58| 59| 60| 61| 62| 63| 64| 65| 66| 67| 68| 69| 70| 71 9| Actinide:| 89| 90| 91| 92| 93| 94| 95| 96| 97| 98| 99|100|101|102|103
Python
A solution trying hard not to encode too much data about the table.
<lang Python> def perta(atomic) -> (int, int):
NOBLES = 2, 10, 18, 36, 54, 86, 118 INTERTWINED = 0, 0, 0, 0, 0, 57, 89 INTERTWINING_SIZE = 14 LINE_WIDTH = 18
prev_noble = 0 for row, noble in enumerate(NOBLES): if atomic <= noble: # we are at the good row. We now need to determine the column nb_elem = noble - prev_noble # number of elements on that row rank = atomic - prev_noble # rank of the input element among elements if INTERTWINED[row] and INTERTWINED[row] <= atomic <= INTERTWINED[row] + INTERTWINING_SIZE: # lantanides or actinides row += 2 col = rank + 1 else: # not a lantanide nor actinide # handle empty spaces between 1-2, 4-5 and 12-13. nb_empty = LINE_WIDTH - nb_elem # spaces count as columns inside_left_element_rank = 2 if noble > 2 else 1 col = rank + (nb_empty if rank > inside_left_element_rank else 0) break prev_noble = noble return row+1, col
- small test suite
TESTS = {
1: (1, 1), 2: (1, 18), 29: (4,11), 42: (5, 6), 58: (8, 5), 59: (8, 6), 57: (8, 4), 71: (8, 18), 72: (6, 4), 89: (9, 4), 90: (9, 5), 103: (9, 18),
}
for input, out in TESTS.items():
found = perta(input) print('TEST:{:3d} -> '.format(input) + str(found) + (f' ; ERROR: expected {out}' if found != out else ))
</lang>
Raku
<lang perl6>my $b = 18; my @offset = 16, 10, 10, (2×$b)+1, (-2×$b)-15, (2×$b)+1, (-2×$b)-15; my @span = flat ^8 Zxx <1 3 8 44 15 17 15 15>;
for <1 2 29 42 57 58 72 89 90 103> -> $n {
printf "%3d: %2d, %2d\n", $n, map {$_+1}, ($n-1 + [+] @offset.head(@span[$n-1])).polymod($b).reverse;
}</lang>
- Output:
1: 1, 1 2: 1, 18 29: 4, 11 42: 5, 6 57: 8, 4 58: 8, 5 72: 6, 4 89: 9, 4 90: 9, 5 103: 9, 18
Wren
There is a discrepancy between how the periodic table is arranged in the Wikipedia article and how it is arranged in the task description. I've used the latter in the following script. <lang ecmascript>import "./fmt" for Fmt
var limits = [3..10, 11..18, 19..36, 37..54, 55..86, 87..118]
var periodicTable = Fn.new { |n|
if (n < 1 || n > 118) Fiber.abort("Atomic number is out of range.") if (n == 1) return [1, 1] if (n == 2) return [1, 18] if (n >= 57 && n <= 71) return [8, n - 53] if (n >= 89 && n <= 103) return [9, n - 85] var row var start var end for (i in 0...limits.count) { var limit = limits[i] if (n >= limit.from && n <= limit.to) { row = i + 2 start = limit.from end = limit.to break } } if (n < start + 2 || row == 4 || row == 5) return [row, n - start + 1] return [row, n - end + 18]
}
for (n in [1, 2, 29, 42, 57, 58, 59, 71, 72, 89, 90, 103, 113]) {
var rc = periodicTable.call(n) Fmt.print("Atomic number $3d -> $d, $-2d", n, rc[0], rc[1])
}</lang>
- Output:
Atomic number 1 -> 1, 1 Atomic number 2 -> 1, 18 Atomic number 29 -> 4, 11 Atomic number 42 -> 5, 6 Atomic number 57 -> 8, 4 Atomic number 58 -> 8, 5 Atomic number 59 -> 8, 6 Atomic number 71 -> 8, 18 Atomic number 72 -> 6, 4 Atomic number 89 -> 9, 4 Atomic number 90 -> 9, 5 Atomic number 103 -> 9, 18 Atomic number 113 -> 7, 13
XPL0
<lang XPL0>proc ShowPosn(N); \Show row and column for element int N, M, A, B, I, R, C; [A:= [ 1, 2, 5, 13, 57, 72, 89, 104]; \magic numbers
B:= [-1, 15, 25, 35, 72, 21, 58, 7];
I:= 7; while A(I) > N do I:= I-1; M:= N + B(I); R:= M/18 +1; C:= rem(0) +1; IntOut(0, N); Text(0, " -> "); IntOut(0, R); Text(0, ", "); IntOut(0, C); CrLf(0); ];
int Element, I; [Element:= [1, 2, 29, 42, 57, 58, 72, 89, 90, 103]; for I:= 0 to 10-1 do ShowPosn(Element(I)); ]</lang>
- Output:
1 -> 1, 1 2 -> 1, 18 29 -> 4, 11 42 -> 5, 6 57 -> 8, 4 58 -> 8, 5 72 -> 6, 4 89 -> 9, 4 90 -> 9, 5 103 -> 9, 18