Wuxings in Positive Action
JavaScript (Node.js), 39 bytes
I/O: Unicode codepoints as integers.
n=>Buffer("99944,777I")[n/543%62&15]<<9
Try it online!
How?
Step 1
We first look for some divisor \$d\$ such that the following element sets \$S_k\$ are disjoint:
$$S_k=\left\{\left\lfloor\dfrac{n}{d}\right\rfloor,\:C_{min}(k)\le n\le C_{max}(k)\right\}$$
where \$C_{min}(k)\$ and \$C_{max}(k)\$ are the codepoint bounds of the \$k\$-th element.
Because the Unicode range of Water (U+6C34 to U+706A) is immediately followed by the Unicode range of Fire (U+706B to U+7229), there are not many possible options for \$d\$: it must be a proper divisor of \$28779\$ (0x706B), i.e. \$d\in\{1, 3, 53, 159, 181, 543, 9593\}\$. The best value in there that actually works is \$d=543\$.
Step 2
We then look for some modulo chain that takes \$n\$ as input and turns it into an index corresponding to the counterpart element, using \$n/543\$. Instead of rounding the result towards zero, we force the last operation to a bitwise AND rather than a modulo.
A quick brute-force search leads to:
$$f(n)=((n/543)\bmod 62)\operatorname{and}15$$
Step 3
Finally, we look for some multiplier \$m\$ such that there exists some \$q_k\$ for each \$k\$ that satisfies:
$$C_{min}(k)\le q_k\times m\le C_{max}(k)$$
One possible golf-friendly value is \$m=512\$, leading to the following table:
element | hexa range | q | q*512 | as hexa
---------+-----------------+----+-------+---------
Soil | 0x571F - 0x58EA | 44 | 22528 | 0x5800
Wood | 0x6728 - 0x6B1F | 52 | 26624 | 0x6800
Water | 0x6C34 - 0x706A | 55 | 28160 | 0x6E00
Fire | 0x706B - 0x7229 | 57 | 29184 | 0x7200
Metal | 0x91D1 - 0x9484 | 73 | 37376 | 0x9200
The values of \$q\$ are encoded as the ASCII codes of ,479I
.
Haskell, 51 bytes
w x="金火林土水"!!sum[1|c<-"朧氳灪釐",x>c]
Try it online!
Jelly, 18 bytes
“Ọ{ƊɠṪƲ‘ɓ:Ḣ<Sịɗ‘×Ḣ
A monadic Link accepting an ordinal which yields an ordinal as below:
Input Output
Fire (28779 火 - 29225 爩) 22444 垬 (Soil)
Soil (22303 土 - 22762 壪) 37467 鉛 (Metal)
Metal (37329 金 - 38020 钄) 27874 波 (Water)
Water (27700 水 - 28778 灪) 26426 机 (Wood)
Wood (26408 木 - 27423 欟) 28960 焠 (Fire)
Try it online! Or see all valid cases.
How?
Integer dividing by \$181\$:
- keeps the ranges distinct
- reduces all values to less than \$256\$
- has more than one result for each range
- has a single result greater than \$181\$
This allows us to place all our magic numbers into a single list of code-page indices, using these for the integer division, the category identification, a lookup of the new category, and a final multiplication:
“Ọ{ƊɠṪƲ‘ɓ:Ḣ<Sịɗ‘×Ḣ - Link: ordinal, n e.g. n = 27700 (木 - minimal Water)
“Ọ{ƊɠṪƲ‘ - code-page indices (call this M) [181,123,145,159,206,153]
ɓ - new dyadic chain - f(n,M):
: - integer divide [27700//181, 27700//123,...]
Ḣ - head (call this x) 27700//181 = 153
ɗ - last three links as a dyad - f(x, M):
< - (x) less than? (M) [1, 0, 0, 1, 1, 0]
S - sum 3
ị - index into (M) 145
‘ - increment 146
× - multiply (M) [146×181, 146×123, ...]
Ḣ - head 146×181 = 26426 (机 - a Wood)