Periodic table: Difference between revisions
SqrtNegInf (talk | contribs) m →{{header|Raku}}: tweaks |
SqrtNegInf (talk | contribs) Add Perl, move Raku |
||
Line 248: | Line 248: | ||
</pre> |
</pre> |
||
=={{header| |
=={{header|Perl}}== |
||
{{trans|Raku}} |
|||
⚫ | |||
<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> |
}</lang> |
||
{{out}} |
{{out}} |
||
Line 384: | Line 393: | ||
</lang> |
</lang> |
||
=={{header|Raku}}== |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
}</lang> |
|||
{{out}} |
|||
<pre> 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</pre> |
|||
=={{header|Wren}}== |
=={{header|Wren}}== |
Revision as of 17:44, 20 June 2022
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
Display the row and column in the periodic table of the given atomic number.
- 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