EnableExplicit
DisableDebugger
DataSection
  LBL_n1:
  Data.i 3,5,7
  LBL_a1:
  Data.i 2,3,2
  LBL_n2:
  Data.i 11,12,13
  LBL_a2:
  Data.i 10,4,12
  LBL_n3:
  Data.i 10,4,9
  LBL_a3:
  Data.i 11,22,19
EndDataSection

Procedure ErrorHdl()
  Print(ErrorMessage())
  Input()
EndProcedure

Macro PrintData(n,a)
  Define Idx.i=0
  Print("[")
  While n+SizeOf(Integer)*Idx<a
    Print("( ")
    Print(Str(PeekI(a+SizeOf(Integer)*Idx)))
    Print(" . ")
    Print(Str(PeekI(n+SizeOf(Integer)*Idx)))
    Print(" )")
    Idx+1
  Wend
  Print(~"]\nx = ")
EndMacro

Procedure.i Produkt_n(n_Adr.i,a_Adr.i)
  Define p.i=1
  While n_Adr<a_Adr
    p*PeekI(n_Adr)
    n_Adr+SizeOf(Integer)
  Wend
  ProcedureReturn p
EndProcedure

Procedure.i Eval_x1(a.i,b.i)
  Define b0.i=b, x0.i=0, x1.i=1, q.i, t.i
  If b=1 : ProcedureReturn x1 : EndIf
  While a>1
    q=Int(a/b)
    t=b : b=a%b : a=t
    t=x0 : x0=x1-q*x0 : x1=t
  Wend
  If x1<0 : ProcedureReturn x1+b0 : EndIf
  ProcedureReturn x1
EndProcedure

Procedure.i ChineseRem(n_Adr.i,a_Adr.i)
  Define prod.i=Produkt_n(n_Adr,a_Adr), a.i, b.i, p.i, Idx.i=0, sum.i
  While n_Adr+SizeOf(Integer)*Idx<a_Adr
    b=PeekI(n_Adr+SizeOf(Integer)*Idx)
    p=Int(prod/b) : a=p
    sum+PeekI(a_Adr+SizeOf(Integer)*Idx)*Eval_x1(a,b)*p
    Idx+1
  Wend
  ProcedureReturn sum%prod
EndProcedure

OnErrorCall(@ErrorHdl())
OpenConsole("Chinese remainder theorem")
PrintData(?LBL_n1,?LBL_a1)
PrintN(Str(ChineseRem(?LBL_n1,?LBL_a1)))
PrintData(?LBL_n2,?LBL_a2)
PrintN(Str(ChineseRem(?LBL_n2,?LBL_a2)))
PrintData(?LBL_n3,?LBL_a3)
PrintN(Str(ChineseRem(?LBL_n3,?LBL_a3)))
Input()


# Python 2.7
def chinese_remainder(n, a):
    sum = 0
    prod = reduce(lambda a, b: a*b, n)

    for n_i, a_i in zip(n, a):
        p = prod / n_i
        sum += a_i * mul_inv(p, n_i) * p
    return sum % prod

def mul_inv(a, b):
    b0 = b
    x0, x1 = 0, 1
    if b == 1: return 1
    while a > 1:
        q = a / b
        a, b = b, a%b
        x0, x1 = x1 - q * x0, x0
    if x1 < 0: x1 += b0
    return x1

if __name__ == '__main__':
    n = [3, 5, 7]
    a = [2, 3, 2]
    print chinese_remainder(n, a)


mul_inv <- function(a, b)
{
  b0 <- b
  x0 <- 0L
  x1 <- 1L

  if (b == 1) return(1L)
  while(a > 1){
    q <- as.integer(a/b)

    t <- b
    b <- a %% b
    a <- t

    t <- x0
    x0 <- x1 - q*x0
    x1 <- t
  }

  if (x1 < 0) x1 <- x1 + b0
  return(x1)
}

chinese_remainder <- function(n, a)
{
  len <- length(n)

  prod <- 1L
  sum <- 0L

  for (i in 1:len) prod <- prod * n[i]

  for (i in 1:len){
    p <- as.integer(prod / n[i])
    sum <- sum + a[i] * mul_inv(p, n[i]) * p
  }

  return(sum %% prod)
}

n <- c(3L, 5L, 7L)
a <- c(2L, 3L, 2L)

chinese_remainder(n, a)


#lang racket
(require (only-in math/number-theory solve-chinese))
(define as '(2 3 2))
(define ns '(3 5 7))
(solve-chinese as ns)


/*REXX program demonstrates  Sun Tzu's  (or Sunzi's)  Chinese Remainder  Theorem.       */
parse arg Ns As .                                /*get optional arguments from the C.L. */
if Ns=='' | Ns==","  then Ns= '3,5,7'            /*Ns not specified?   Then use default.*/
if As=='' | As==","  then As= '2,3,2'            /*As  "      "          "   "      "   */
       say 'Ns: '  Ns
       say 'As: '  As;             say
Ns= space( translate(Ns, , ','));  #= words(Ns)  /*elide any superfluous blanks from N's*/
As= space( translate(As, , ','));  _= words(As)  /*  "    "       "        "      "  A's*/
if #\==_   then do;  say  "size of number sets don't match.";   exit 131;    end
if #==0    then do;  say  "size of the  N  set isn't valid.";   exit 132;    end
if _==0    then do;  say  "size of the  A  set isn't valid.";   exit 133;    end
N= 1                                             /*the product─to─be  for  prod(n.j).   */
      do j=1  for #                              /*process each number for  As  and Ns. */
      n.j= word(Ns, j);   N= N * n.j             /*get an  N.j  and calculate product.  */
      a.j= word(As, j)                           /* "   "  A.j  from the  As  list.     */
      end      /*j*/

      do    x=1  for N                           /*use a simple algebraic method.       */
         do i=1  for #                           /*process each   N.i  and  A.i  number.*/
         if x//n.i\==a.i  then iterate x         /*is modulus correct for the number X ?*/
         end   /*i*/                             /* [↑]  limit solution to the product. */
      say 'found a solution with X='   x         /*display one possible solution.       */
      exit 0                                     /*stick a fork in it,  we're all done. */
      end      /*x*/

say 'no solution found.'                         /*oops, announce that solution ¬ found.*/


def chinese_remainder(mods, remainders)
  max = mods.inject( :* )
  series = remainders.zip( mods ).map{|r,m| r.step( max, m ).to_a }
  series.inject( :& ).first #returns nil when empty
end

p chinese_remainder([3,5,7], [2,3,2])     #=> 23
p chinese_remainder([10,4,9], [11,22,19]) #=> nil


fn egcd(a: i64, b: i64) -> (i64, i64, i64) {
    if a == 0 {
        (b, 0, 1)
    } else {
        let (g, x, y) = egcd(b % a, a);
        (g, y - (b / a) * x, x)
    }
}

fn mod_inv(x: i64, n: i64) -> Option<i64> {
    let (g, x, _) = egcd(x, n);
    if g == 1 {
        Some((x % n + n) % n)
    } else {
        None
    }
}

fn chinese_remainder(residues: &[i64], modulii: &[i64]) -> Option<i64> {
    let prod = modulii.iter().product::<i64>();

    let mut sum = 0;

    for (&residue, &modulus) in residues.iter().zip(modulii) {
        let p = prod / modulus;
        sum += residue * mod_inv(p, modulus)? * p
    }

    Some(sum % prod)
}

fn main() {
    let modulii = [3,5,7];
    let residues = [2,3,2];

    match chinese_remainder(&residues, &modulii) {
        Some(sol) => println!("{}", sol),
        None      => println!("modulii not pairwise coprime")
    }

}


import scala.util.{Success, Try}

object ChineseRemainderTheorem extends App {

  def chineseRemainder(n: List[Int], a: List[Int]): Option[Int] = {
    require(n.size == a.size)
    val prod = n.product

    def iter(n: List[Int], a: List[Int], sm: Int): Int = {
      def mulInv(a: Int, b: Int): Int = {
        def loop(a: Int, b: Int, x0: Int, x1: Int): Int = {
          if (a > 1) loop(b, a % b, x1 - (a / b) * x0, x0) else x1
        }

        if (b == 1) 1
        else {
          val x1 = loop(a, b, 0, 1)
          if (x1 < 0) x1 + b else x1
        }
      }

      if (n.nonEmpty) {
        val p = prod / n.head

        iter(n.tail, a.tail, sm + a.head * mulInv(p, n.head) * p)
      } else sm
    }

    Try {
      iter(n, a, 0) % prod
    } match {
      case Success(v) => Some(v)
      case _          => None
    }
  }

  println(chineseRemainder(List(3, 5, 7), List(2, 3, 2)))
  println(chineseRemainder(List(11, 12, 13), List(10, 4, 12)))
  println(chineseRemainder(List(11, 22, 19), List(10, 4, 9)))

}


$ include "seed7_05.s7i";
  include "bigint.s7i";

const func integer: modInverse (in integer: a, in integer: b) is
  return ord(modInverse(bigInteger conv a, bigInteger conv b));

const proc: main is func
  local
    const array integer: n is [] (3, 5, 7);
    const array integer: a is [] (2, 3, 2);
    var integer: num is 0;
    var integer: prod is 1;
    var integer: sum is 0;
    var integer: index is 0;
  begin
    for num range n do
      prod *:= num;
    end for;
    for key index range a do
      num := prod div n[index];
      sum +:= a[index] * modInverse(num, n[index]) * num;
    end for;
    writeln(sum mod prod);
  end func;


func chinese_remainder(*n) {
    var N = n.prod
    func (*a) {
        n.range.sum { |i|
            var p = (N / n[i])
            a[i] * p.invmod(n[i]) * p
        } % N
    }
}

say chinese_remainder(3, 5, 7)(2, 3, 2)


CREATE TEMPORARY TABLE inputs(remainder INT, modulus INT);

INSERT INTO inputs VALUES (2, 3), (3, 5), (2, 7);

WITH recursive

-- Multiply out the product of moduli
multiplication(idx, product) AS (
    SELECT 1, 1

    UNION ALL

    SELECT
        multiplication.idx+1,
        multiplication.product * inputs.modulus
    FROM
        multiplication,
        inputs
    WHERE
        inputs.rowid = multiplication.idx
),

-- Take the final value from the product table
product(final_value) AS (
    SELECT MAX(product) FROM multiplication
),

-- Calculate the multiplicative inverse from each equation
multiplicative_inverse(id, a, b, x, y) AS (
    SELECT
        inputs.modulus,
        product.final_value / inputs.modulus,
        inputs.modulus,
        0,
        1
    FROM
        inputs,
        product

    UNION ALL

    SELECT
        id,
        b, a%b,
        y - (a/b)*x, x
    FROM
        multiplicative_inverse
    WHERE
        a>0
)
-- Combine residues into final answer
SELECT
    SUM(
        (y % inputs.modulus) * inputs.remainder * (product.final_value / inputs.modulus)
    ) % product.final_value
  FROM
    multiplicative_inverse, product, inputs
  WHERE
    a=1 AND multiplicative_inverse.id = inputs.modulus;


import Darwin

/*
 * Function: euclid
 * Usage: (r,s) = euclid(m,n)
 * --------------------------
 * The extended Euclidean algorithm subsequently performs
 * Euclidean divisions till the remainder is zero and then
 * returns the Bézout coefficients r and s.
 */

func euclid(_ m:Int, _ n:Int) -> (Int,Int) {
    if m % n == 0 {
        return (0,1)
    } else {
        let rs = euclid(n % m, m)
        let r = rs.1 - rs.0 * (n / m)
        let s = rs.0

        return (r,s)
    }
}

/*
 * Function: gcd
 * Usage: x = gcd(m,n)
 * -------------------
 * The greatest common divisor of two numbers a and b
 * is expressed by ax + by = gcd(a,b) where x and y are
 * the Bézout coefficients as determined by the extended
 * euclidean algorithm.
 */

func gcd(_ m:Int, _ n:Int) -> Int {
    let rs = euclid(m, n)
    return m * rs.0 + n * rs.1
}

/*
 * Function: coprime
 * Usage: truth = coprime(m,n)
 * ---------------------------
 * If two values are coprime, their greatest common
 * divisor is 1.
 */

func coprime(_ m:Int, _ n:Int) -> Bool {
    return gcd(m,n) == 1 ? true : false
}

coprime(14,26)
//coprime(2,4)

/*
 * Function: crt
 * Usage: x = crt(a,n)
 * -------------------
 * The Chinese Remainder Theorem supposes that given the
 * integers n_1...n_k that are pairwise co-prime, then for
 * any sequence of integers a_1...a_k there exists an integer
 * x that solves the system of linear congruences:
 *
 *   x === a_1 (mod n_1)
 *   ...
 *   x === a_k (mod n_k)
 */

func crt(_ a_i:[Int], _ n_i:[Int]) -> Int {
    // There is no identity operator for elements of [Int].
    // The offset of the elements of an enumerated sequence
    // can be used instead, to determine if two elements of the same
    // array are the same.
    let divs = n_i.enumerated()

    // Check if elements of n_i are pairwise coprime divs.filter{ $0.0 < n.0 }
    divs.forEach{
        n in divs.filter{ $0.0 < n.0 }.forEach{
            assert(coprime(n.1, $0.1))
        }
    }

    // Calculate factor N
    let N = n_i.map{$0}.reduce(1, *)

    // Euclidean algorithm determines s_i (and r_i)
    var s:[Int] = []

    // Using euclidean algorithm to calculate r_i, s_i
    n_i.forEach{ s += [euclid($0, N / $0).1] }

    // Solve for x
    var x = 0
    a_i.enumerated().forEach{
        x += $0.1 * s[$0.0] * N / n_i[$0.0]
    }

    // Return minimal solution
    return x % N
}

let a = [2,3,2]
let n = [3,5,7]

let x = crt(a,n)

print(x)


proc ::tcl::mathfunc::mulinv {a b} {
    if {$b == 1} {return 1}
    set b0 $b; set x0 0; set x1 1
    while {$a > 1} {
	set x0 [expr {$x1 - ($a / $b) * [set x1 $x0]}]
	set b [expr {$a % [set a $b]}]
    }
    incr x1 [expr {($x1 < 0) * $b0}]
}
proc chineseRemainder {nList aList} {
    set sum 0; set prod [::tcl::mathop::* {*}$nList]
    foreach n $nList a $aList {
	set p [expr {$prod / $n}]
	incr sum [expr {$a * mulinv($p, $n) * $p}]
    }
    expr {$sum % $prod}
}
puts [chineseRemainder {3 5 7} {2 3 2}]


@(000) = 3 : @(001) = 5 : @(002) = 7
@(100) = 2 : @(101) = 3 : @(102) = 2

Print Func (_Chinese_Remainder (3))

' -------------------------------------

@(000) = 11 : @(001) = 12 : @(002) = 13
@(100) = 10 : @(101) = 04 : @(102) = 12

Print Func (_Chinese_Remainder (3))

' -------------------------------------

End

                                       ' returns x where (a * x) % b == 1
_Mul_Inv Param (2)                     ' ( a b -- n)
  Local (4)

  [email protected] = [email protected]
  [email protected] = 0
  [email protected] = 1

  If [email protected] = 1 Then Return (1)

  Do While [email protected] > 1
     [email protected] = [email protected] / [email protected]
     Push [email protected] : [email protected] = [email protected] % [email protected] : [email protected] = Pop()
     Push [email protected] : [email protected] = [email protected] - [email protected] * [email protected] : [email protected] = Pop()
  Loop

  If [email protected] < 0 Then [email protected] = [email protected] + [email protected]

Return ([email protected])

_Chinese_Remainder Param (1)           ' ( len -- n)
  Local (5)

  [email protected] = 1
  [email protected] = 0

  For [email protected] = 0 Step 1 While [email protected] < [email protected]
    [email protected] = [email protected] * @([email protected])
  Next

  For [email protected] = 0 Step 1 While [email protected] < [email protected]
    [email protected] = [email protected] / @([email protected])
    [email protected] = [email protected] + (@(100 + [email protected]) * Func (_Mul_Inv ([email protected], @([email protected]))) * [email protected])
  Next

Return ([email protected] % [email protected])


Private Function chinese_remainder(n As Variant, a As Variant) As Variant
    Dim p As Long, prod As Long, tot As Long
    prod = 1: tot = 0
    For i = 1 To UBound(n)
        prod = prod * n(i)
    Next i
    Dim m As Variant
    For i = 1 To UBound(n)
        p = prod / n(i)
        m = mul_inv(p, n(i))
        If WorksheetFunction.IsText(m) Then
            chinese_remainder = "fail"
            Exit Function
        End If
        tot = tot + a(i) * m * p
    Next i
    chinese_remainder = tot Mod prod
End Function
Public Sub re()
    Debug.Print chinese_remainder([{3,5,7}], [{2,3,2}])
    Debug.Print chinese_remainder([{11,12,13}], [{10,4,12}])
    Debug.Print chinese_remainder([{11,22,19}], [{10,4,9}])
    Debug.Print chinese_remainder([{100,23}], [{19,0}])
End Sub


Module Module1

    Function ModularMultiplicativeInverse(a As Integer, m As Integer) As Integer
        Dim b = a Mod m
        For x = 1 To m - 1
            If (b * x) Mod m = 1 Then
                Return x
            End If
        Next
        Return 1
    End Function

    Function Solve(n As Integer(), a As Integer()) As Integer
        Dim prod = n.Aggregate(1, Function(i, j) i * j)
        Dim sm = 0
        Dim p As Integer
        For i = 0 To n.Length - 1
            p = prod / n(i)
            sm = sm + a(i) * ModularMultiplicativeInverse(p, n(i)) * p
        Next
        Return sm Mod prod
    End Function

    Sub Main()
        Dim n = {3, 5, 7}
        Dim a = {2, 3, 2}

        Dim result = Solve(n, a)

        Dim counter = 0
        Dim maxCount = n.Length - 1
        While counter <= maxCount
            Console.WriteLine($"{result} = {a(counter)} (mod {n(counter)})")
            counter = counter + 1
        End While
    End Sub

End Module


/* returns x where (a * x) % b == 1 */
var mulInv = Fn.new { |a, b|
    if (b == 1) return 1
    var b0 = b
    var x0 = 0
    var x1 = 1
    while (a > 1) {
        var q = (a/b).floor
        var t = b
        b = a % b
        a = t
        t = x0
        x0 = x1 - q*x0
        x1 = t
    }
    if (x1 < 0) x1 = x1 + b0
    return x1
}

var chineseRemainder = Fn.new { |n, a|
    var prod = n.reduce { |acc, i| acc * i }
    var sum = 0
    for (i in 0...n.count) {
        var p = (prod/n[i]).floor
        sum = sum + a[i]*mulInv.call(p, n[i])*p
    }
    return sum % prod
}

var n = [3, 5, 7]
var a = [2, 3, 2]
System.print(chineseRemainder.call(n, a))


var BN=Import("zklBigNum"), one=BN(1);

fcn crt(xs,ys){
   p:=xs.reduce('*,BN(1));
   X:=BN(0);
   foreach x,y in (xs.zip(ys)){
      q:=p/x;
      z,s,_:=q.gcdExt(x);
      if(z!=one) throw(Exception.ValueError("%d not coprime".fmt(x)));
      X+=y*s*q;
   }
   return(X % p);
}


10 DIM n(3): DIM a(3)
20 FOR i=1 TO 3
30 READ n(i),a(i)
40 NEXT i
50 DATA 3,2,5,3,7,2
100 LET prod=1: LET sum=0
110 FOR i=1 TO 3: LET prod=prod*n(i): NEXT i
120 FOR i=1 TO 3
130 LET p=INT (prod/n(i)): LET a=p: LET b=n(i)
140 GO SUB 1000
150 LET sum=sum+a(i)*x1*p
160 NEXT i
170 PRINT FN m(sum,prod)
180 STOP
200 DEF FN m(a,b)=a-INT (a/b)*b: REM Modulus function
1000 LET b0=b: LET x0=0: LET x1=1
1010 IF b=1 THEN RETURN
1020 IF a<=1 THEN GO TO 1100
1030 LET q=INT (a/b)
1040 LET t=b: LET b=FN m(a,b): LET a=t
1050 LET t=x0: LET x0=x1-q*x0: LET x1=t
1060 GO TO 1020
1100 IF x1<0 THEN LET x1=x1+b0
1110 RETURN


V animals = [‘Rat’, ‘Ox’, ‘Tiger’, ‘Rabbit’, ‘Dragon’, ‘Snake’, ‘Horse’, ‘Goat’, ‘Monkey’, ‘Rooster’, ‘Dog’, ‘Pig’]
V elements = [‘Wood’, ‘Fire’, ‘Earth’, ‘Metal’, ‘Water’]

F getElement(year)
   R :elements[(year - 4) % 10 I/ 2]

F getAnimal(year)
   R :animals[(year - 4) % 12]

F getYY(year)
   I year % 2 == 0
      R ‘yang’
   E
      R ‘yin’

L(year) [1935, 1938, 1968, 1972, 1976, 2017]
   print(year‘ is the year of the ’getElement(year)‘ ’getAnimal(year)‘ (’getYY(year)‘).’)


*        Chinese zodiac            10/03/2019
CHINEZOD CSECT
         USING  CHINEZOD,R13       base register
         B      72(R15)            skip savearea
         DC     17F'0'             savearea
         SAVE   (14,12)            save previous context
         ST     R13,4(R15)         link backward
         ST     R15,8(R13)         link forward
         LR     R13,R15            set addressability
         LA     R6,1               i=1
       DO WHILE=(C,R6,LE,=A(NY))   do i=1 to hbound(years)
         LR     R1,R6                i
         SLA    R1,2                 *4
         L      R2,YEARS-4(R1)       ~
         ST     R2,YEAR              year=years(i)
         SH     R2,=H'4'             -4
         LR     R7,R2                year-4
         SRDA   R2,32                ~
         D      R2,=F'10'            /10
         SRA    R2,1                 /2
         MH     R2,=H'6'             *6
         LA     R1,ELEMENTS(R2)      ~
         MVC    ELEMENT,0(R1)      element=elements(mod(year-4,10)/2+1)
         LR     R2,R7                year-4
         SRDA   R2,32                ~
         D      R2,=F'12'            /12
         SLA    R2,3                 *8
         LA     R1,ANIMALS(R2)       ~
         MVC    ANIMAL,0(R1)         animal=animals(mod(year-4,12)+1)
         L      R2,YEAR              year
         SRDA   R2,32                ~
         D      R2,=F'2'             /2
         SLA    R2,2                 *4
         LA     R1,YINYANGS(R2)      ~
         MVC    YINYANG,0(R1)        yinyang=yinyangs(mod(year,2)+1)
         LR     R2,R7                year-4
         SRDA   R2,32                ~
         D      R2,=F'60'            /60
         LA     R2,1(R2)             nn=mod(year-4,60)+1
         L      R1,YEAR              year
         XDECO  R1,XDEC              edit year
         MVC    PG+00(4),XDEC+8      output year
         MVC    PG+24(6),ELEMENT     output element
         MVC    PG+31(8),ANIMAL      output animal
         MVC    PG+41(4),YINYANG     output yinyang
         XDECO  R2,XDEC              edit nn
         MVC    PG+49(2),XDEC+10     output nn
         XPRNT  PG,L'PG              print buffer
         LA     R6,1(R6)             i++
       ENDDO    ,                  enddo i
         L      R13,4(0,R13)       restore previous savearea pointer
         RETURN (14,12),RC=0       restore registers from calling sav
NY       EQU    (ANIMAL-YEARS)/4
ANIMALS  DC     CL8'Rat',CL8'Ox',CL8'Tiger',CL8'Rabbit'
         DC     CL8'Dragon',CL8'Snake',CL8'Horse',CL8'Goat'
         DC     CL8'Monkey',CL8'Rooster',CL8'Dog',CL8'Pig'
ELEMENTS DC     CL6'Wood',CL6'Fire',CL6'Earth',CL6'Metal',CL6'Water'
YINYANGS DC     CL4'Yang',CL4'Yin'
YEARS    DC     F'1935',F'1938',F'1968',F'1972',F'1976',F'1984',F'2017'
ANIMAL   DS     CL8
ELEMENT  DS     CL6
YINYANG  DS     CL4
YEAR     DS     F
PG    DC   CL80':::: is the year of the :::::: :::::::: (::::).  ::/60'
XDEC     DS     CL12               temp for xdeco
         REGEQU
         END    CHINEZOD


DEFINE PTR="CARD"

PTR ARRAY animals(12),elements(5),stems(10),branches(12),yinYangs(2)

PROC Init()
  animals(0)="Rat"    animals(1)="Ox"
  animals(2)="Tiger"  animals(3)="Rabbit"
  animals(4)="Dragon" animals(5)="Snake"
  animals(6)="Horse"  animals(7)="Goat"
  animals(8)="Monkey" animals(9)="Rooster"
  animals(10)="Dog"   animals(11)="Pig"
  elements(0)="Wood"  elements(1)="Fire"
  elements(2)="Earth" elements(3)="Metal"
  elements(4)="Water"
  stems(0)="jia"      stems(1)="yi"
  stems(2)="bing"     stems(3)="ding"
  stems(4)="wu"       stems(5)="ji"
  stems(6)="geng"     stems(7)="xin"
  stems(8)="ren"      stems(9)="gui"
  branches(0)="zi"    branches(1)="chou"
  branches(2)="yin"   branches(3)="mao"
  branches(4)="chen"  branches(5)="si"
  branches(6)="wu"    branches(7)="wei"
  branches(8)="shen"  branches(9)="you"
  branches(10)="xu"   branches(11)="hai"
  yinYangs(0)="Yang"  yinYangs(1)="Yin"
RETURN

PTR FUNC GetAnimal(INT y)
RETURN (animals((y-4) MOD 12))

PTR FUNC GetElement(INT y)
RETURN (elements(((y-4) MOD 10)/2))

PTR FUNC GetStem(INT y)
RETURN (stems((y-4) MOD 10))

PTR FUNC GetBranch(INT y)
RETURN (branches((y-4) MOD 12))

PTR FUNC GetYinYang(INT y)
RETURN (yinYangs(y MOD 2))

BYTE FUNC GetCycle(INT y)
RETURN ((y-4) MOD 60+1)

PROC Main()
  INT ARRAY years=[1935 1938 1968 1972 1976 1984 2017 2021]
  CHAR ARRAY s
  BYTE i,c
  INT y

  Init()
  FOR i=0 TO 7
  DO
    y=years(i)
    PrintI(y) Print(" ")
    s=GetStem(y) Print(s) Print("-")
    s=GetBranch(y) Print(s) Print(" ")
    s=GetElement(y) Print(s) Print(" ")
    s=GetAnimal(y) Print(s) Print(" ")
    s=GetYinYang(y) Print(s) Print(" ")
    c=GetCycle(y) PrintB(c) Print("/60") PutE()
  OD
RETURN


with Ada.Text_IO; 	    use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure Main is

	type Element_Index is mod 5;
	type Animal_Index  is mod 12;
	type Stem_Index    is mod 10;

	type Animal_Array  is array(Animal_Index  range <>) of Unbounded_String;
	type Element_Array is array(Element_Index range <>) of Unbounded_String;
	type Stem_Array    is array(Stem_Index    range <>) of Unbounded_String;

	Ani_Arr : 	Animal_Array 	:= 	(To_Unbounded_String ("Rat"),
						 To_Unbounded_String ("Ox"),
						 To_Unbounded_String ("Tiger"),
						 To_Unbounded_String ("Rabbit"),
						 To_Unbounded_String ("Dragon"),
						 To_Unbounded_String ("Snake"),
						 To_Unbounded_String ("Horse"),
						 To_Unbounded_String ("Sheep"),
						 To_Unbounded_String ("Monkey"),
						 To_Unbounded_String ("Rooster"),
						 To_Unbounded_String ("Dog"),
						 To_Unbounded_String ("Pig"));

	Bra_Arr :	Animal_Array	:=      (To_Unbounded_String ("子"),
					         To_Unbounded_String ("丑"),
					         To_Unbounded_String ("寅"),
				                 To_Unbounded_String ("卯"),
					         To_Unbounded_String ("辰"),
					         To_Unbounded_String ("巳"),
					         To_Unbounded_String ("午"),
					         To_Unbounded_String ("未"),
					         To_Unbounded_String ("申"),
					         To_Unbounded_String ("酉"),
					         To_Unbounded_String ("戌"),
					         To_Unbounded_String ("亥"));

	Ele_Arr : 	Element_Array 	:= 	(To_Unbounded_String ("Wood"),
						 To_Unbounded_String ("Fire"),
						 To_Unbounded_String ("Earth"),
						 To_Unbounded_String ("Metal"),
						 To_Unbounded_String ("Water"));

	Ste_Arr :	Stem_Array	:= 	(To_Unbounded_String ("甲"),
						 To_Unbounded_String ("乙"),
						 To_Unbounded_String ("丙"),
						 To_Unbounded_String ("丁"),
						 To_Unbounded_String ("戊"),
						 To_Unbounded_String ("己"),
						 To_Unbounded_String ("庚"),
						 To_Unbounded_String ("辛"),
						 To_Unbounded_String ("壬"),
						 To_Unbounded_String ("癸"));

	procedure Sexagenary (Year : Positive) is
		Base_Year : Positive := 1984;
		Temp      : Natural  := abs (Base_Year - Year);
		Temp_Float: Float    := 0.0;

		Ele_Idx   : Element_Index    := Element_Index'First;
		Ani_Idx   : Animal_Index     := Animal_Index'First;
		Ste_Idx   : Stem_Index       := Stem_Index'First;
		Result    : Unbounded_String := Null_Unbounded_String;
		begin
			Result := Result & Year'Image & " is the year of ";

			if Year >= Base_Year then
				Temp_Float := Float'Floor (Float (Temp) / Float (2));
				Ele_Idx    := Element_Index (Natural (Temp_Float) mod 5);
				Result     := Result & Ele_Arr (Ele_Idx) & " ";

				Ani_Idx := Animal_Index (Temp mod 12);
				Result  := Result & Ani_Arr (Ani_Idx) & " ";
			elsif Year < Base_Year then
				Temp_Float := Float'Ceiling (Float (Temp) / Float (2));
				Ele_Idx    := Ele_Idx - Element_Index (Natural (Temp_Float) mod 5);
				Result     := Result & Ele_Arr (Ele_Idx) & " ";

				Ani_Idx := Ani_Idx - Animal_Index (Temp mod 12);
				Result  := Result & Ani_Arr (Ani_Idx) & " ";
			end if;

			if Year mod 2 = 0 then
				Result := Result & "(yang). ";
			else
				Result := Result & "(yin). ";
			end if;

			Ani_Idx := Animal_Index'First;

			if Year >= Base_Year then
				Ste_Idx := Stem_Index (Temp mod 10);
				Result  := Result & Ste_Arr (Ste_Idx);

				Ani_Idx := Animal_Index (Temp mod 12);
				Result  := Result & Bra_Arr (Ani_Idx);
			elsif Year < Base_Year then
				Ste_Idx := Ste_Idx - Stem_Index (Temp mod 10);
				Result  := Result & Ste_Arr (Ste_Idx);

				Ani_Idx := Ani_Idx - Animal_Index (Temp mod 12);
				Result  := Result & Bra_Arr (Ani_Idx);
			end if;

			Put (To_String (Result));
	end Sexagenary;

    arr : array(Positive range <>) of Positive := (1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017);
begin
    for I of arr loop
        Sexagenary (I);
        New_Line;
    end loop;
end Main;


BEGIN # Chinese Zodiac #
    # returns s right-padded with blanks to w characters, or s if s is already at least w characters long #
    PRIO PAD = 1;
    OP   PAD = ( STRING s, INT w )STRING:
         BEGIN
            STRING result := s;
            WHILE ( ( UPB result + 1 ) - LWB s ) < w DO result +:= " " OD;
            result
         END # PAD # ;
    []STRING animal name  = ( "Rat",   "Ox",   "Tiger",  "Rabbit",  "Dragon", "Snake"
                            , "Horse", "Goat", "Monkey", "Rooster", "Dog",    "Pig"
                            );
    []STRING element name = ( "Wood",  "Fire", "Earth",  "Metal",   "Water" );
    []INT    test year    = ( 1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017 );
    print( ( "year element animal  aspect", newline ) );
    FOR i FROM LWB test year TO UPB test year DO
        INT    year    = test year[ i ];
        STRING element = element name[ ( ( year - 4 ) MOD 10 OVER 2 ) + 1 ];
        STRING animal  = animal name[    ( year - 4 ) MOD 12          + 1 ];
        STRING yy      = IF ODD year THEN "Yin" ELSE "Yang" FI;
        print( ( whole( year, -4 ), " ", element PAD 7, " ", animal PAD 7, " ", yy, newline ) )
    OD
END


on run

    -- TRADITIONAL STRINGS ---------------------------------------------------

    -- ts :: Array Int (String, String)            -- 天干 tiangan – 10 heavenly stems
    set ts to zip(chars("甲乙丙丁戊己庚辛壬癸"), ¬
        |words|("jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi"))

    -- ds :: Array Int (String, String)            -- 地支 dizhi – 12 terrestrial branches
    set ds to zip(chars("子丑寅卯辰巳午未申酉戌亥"), ¬
        |words|("zĭ chŏu yín măo chén sì wŭ wèi shēn yŏu xū hài"))

    -- ws :: Array Int (String, String, String)    -- 五行 wuxing – 5 elements
    set ws to zip3(chars("木火土金水"), ¬
        |words|("mù huǒ tǔ jīn shuǐ"), ¬
        |words|("wood fire earth metal water"))

    -- xs :: Array Int (String, String, String)    -- 十二生肖 shengxiao – 12 symbolic animals
    set xs to zip3(chars("鼠牛虎兔龍蛇馬羊猴鸡狗豬"), ¬
        |words|("shǔ niú hǔ tù lóng shé mǎ yáng hóu jī gǒu zhū"), ¬
        |words|("rat ox tiger rabbit dragon snake horse goat monkey rooster dog pig"))

    -- ys :: Array Int (String, String)            -- 阴阳 yinyang
    set ys to zip(chars("阳阴"), |words|("yáng yīn"))

    -- TRADITIONAL CYCLES ----------------------------------------------------

    script cycles
        on |λ|(y)
            set iYear to y - 4
            set iStem to iYear mod 10
            set iBranch to iYear mod 12
            set {hStem, pStem} to item (iStem + 1) of ts
            set {hBranch, pBranch} to item (iBranch + 1) of ds
            set {hElem, pElem, eElem} to item ((iStem div 2) + 1) of ws
            set {hAnimal, pAnimal, eAnimal} to item (iBranch + 1) of xs
            set {hYinyang, pYinyang} to item ((iYear mod 2) + 1) of ys

            {{show(y), hStem & hBranch, hElem, hAnimal, hYinyang}, ¬
                {"", pStem & pBranch, pElem, pAnimal, pYinyang}, ¬
                {"", show((iYear mod 60) + 1) & "/60", eElem, eAnimal, ""}}
        end |λ|
    end script

    -- FORMATTING ------------------------------------------------------------

    -- fieldWidths :: [[Int]]
    set fieldWidths to {{6, 10, 7, 8, 3}, {6, 11, 8, 8, 4}, {6, 11, 8, 8, 4}}

    script showYear
        script widthStringPairs
            on |λ|(nscs)
                set {ns, cs} to nscs
                zip(ns, cs)
            end |λ|
        end script

        script justifiedRow
            on |λ|(row)
                script
                    on |λ|(ns)
                        set {n, s} to ns
                        justifyLeft(n, space, s)
                    end |λ|
                end script

                concat(map(result, row))
            end |λ|
        end script

        on |λ|(y)
            unlines(map(justifiedRow, ¬
                map(widthStringPairs, ¬
                    zip(fieldWidths, |λ|(y) of cycles))))
        end |λ|
    end script

    -- TEST OUTPUT -----------------------------------------------------------
    intercalate("\n\n", map(showYear, {1935, 1938, 1968, 1972, 1976, 1984, 2017}))
end run

-- GENERIC FUNCTIONS ---------------------------------------------------------

-- chars :: String -> [String]
on chars(s)
    characters of s
end chars

-- concat :: [[a]] -> [a] | [String] -> String
on concat(xs)
    if length of xs > 0 and class of (item 1 of xs) is string then
        set acc to ""
    else
        set acc to {}
    end if
    repeat with i from 1 to length of xs
        set acc to acc & item i of xs
    end repeat
    acc
end concat

-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl

-- intercalate :: Text -> [Text] -> Text
on intercalate(strText, lstText)
    set {dlm, my text item delimiters} to {my text item delimiters, strText}
    set strJoined to lstText as text
    set my text item delimiters to dlm
    return strJoined
end intercalate

-- justifyLeft :: Int -> Char -> Text -> Text
on justifyLeft(n, cFiller, strText)
    if n > length of strText then
        text 1 thru n of (strText & replicate(n, cFiller))
    else
        strText
    end if
end justifyLeft

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- min :: Ord a => a -> a -> a
on min(x, y)
    if y < x then
        y
    else
        x
    end if
end min

-- minimum :: [a] -> a
on minimum(xs)
    script min
        on |λ|(a, x)
            if x < a or a is missing value then
                x
            else
                a
            end if
        end |λ|
    end script

    foldl(min, missing value, xs)
end minimum

-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- Egyptian multiplication - progressively doubling a list, appending
-- stages of doubling to an accumulator where needed for binary
-- assembly of a target length

-- replicate :: Int -> a -> [a]
on replicate(n, a)
    set out to {}
    if n < 1 then return out
    set dbl to {a}

    repeat while (n > 1)
        if (n mod 2) > 0 then set out to out & dbl
        set n to (n div 2)
        set dbl to (dbl & dbl)
    end repeat
    return out & dbl
end replicate

-- show :: a -> String
on show(e)
    set c to class of e
    if c = list then
        script serialized
            on |λ|(v)
                show(v)
            end |λ|
        end script

        "[" & intercalate(", ", map(serialized, e)) & "]"
    else if c = record then
        script showField
            on |λ|(kv)
                set {k, ev} to kv
                "\"" & k & "\":" & show(ev)
            end |λ|
        end script

        "{" & intercalate(", ", ¬
            map(showField, zip(allKeys(e), allValues(e)))) & "}"
    else if c = date then
        "\"" & iso8601Z(e) & "\""
    else if c = text then
        "\"" & e & "\""
    else if (c = integer or c = real) then
        e as text
    else if c = class then
        "null"
    else
        try
            e as text
        on error
            ("«" & c as text) & "»"
        end try
    end if
end show

-- unlines :: [String] -> String
on unlines(xs)
    intercalate(linefeed, xs)
end unlines

-- words :: String -> [String]
on |words|(s)
    words of s
end |words|

-- zip :: [a] -> [b] -> [(a, b)]
on zip(xs, ys)
    set lng to min(length of xs, length of ys)
    set lst to {}
    repeat with i from 1 to lng
        set end of lst to {item i of xs, item i of ys}
    end repeat
    return lst
end zip

-- zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
on zip3(xs, ys, zs)
    script
        on |λ|(x, i)
            [x, item i of ys, item i of zs]
        end |λ|
    end script

    map(result, items 1 thru ¬
        minimum({length of xs, length of ys, length of zs}) of xs)
end zip3


Chinese_zodiac(year){
	Animal		:= StrSplit("Rat,Ox,Tiger,Rabbit,Dragon,Snake,Horse,Goat,Monkey,Rooster,Dog,Pig", ",")
	AnimalCh	:= StrSplit("鼠牛虎兔龍蛇馬羊猴鸡狗豬")
	AnimalName	:= StrSplit("shǔ,niú,hǔ,tù,lóng,shé,mǎ,yáng,hóu,jī,gǒu,zhū", ",")
	Element		:= StrSplit("Wood,Fire,Earth,Metal,Water", ",")
	ElementCh	:= StrSplit("木火土金水")
	ElementName	:= StrSplit("mù,huǒ,tǔ,jīn,shuǐ", ",")
	StemCh		:= StrSplit("甲乙丙丁戊己庚辛壬癸")
	StemName	:= StrSplit("jiă,yĭ,bĭng,dīng,wù,jĭ,gēng,xīn,rén,gŭi", ",")
	BranchCh	:= StrSplit("子丑寅卯辰巳午未申酉戌亥")
	BranchName	:= StrSplit("zĭ,chŏu,yín,măo,chén,sì,wŭ,wèi,shēn,yŏu,xū,hài", ",")
	Mod10	:= Mod(year-4, 10)+1
	Mod12	:= Mod(year-4, 12)+1
	A	:= Animal[Mod12],
	Ac	:= AnimalCh[Mod12]
	An	:= AnimalName[Mod12]
	E	:= Element[Floor(Mod(year-4, 10)/2+1)]
	Ec	:= ElementCh[Floor(Mod(year-4, 10)/2+1)]
	En	:= ElementName[Floor(Mod(year-4, 10)/2+1)]
	YY	:= Mod(year-4, 2)=1 ? "yīn 阴" : "yáng 阳"
	Yr	:= Mod(year-4, 60)+1 "/60"
	S	:= StemCh[Mod10]
	Sn	:= StemName[Mod10]
	B	:= BranchCh[Mod12]
	Bn	:= BranchName[Mod12]
	return year "`t" S B " " Sn "-" Bn " `t" E " " Ec " " En "`t" A " " Ac " " An "`t" YY " " Yr
}


# syntax: GAWK -f CHINESE_ZODIAC.AWK
BEGIN {
    print("year element animal  aspect")
    split("Rat,Ox,Tiger,Rabbit,Dragon,Snake,Horse,Goat,Monkey,Rooster,Dog,Pig",animal_arr,",")
    split("Wood,Fire,Earth,Metal,Water",element_arr,",")
    n = split("1935,1938,1968,1972,1976,1984,1985,2017",year_arr,",")
    for (i=1; i<=n; i++) {
      year = year_arr[i]
      element = element_arr[int((year-4)%10/2)+1]
      animal = animal_arr[(year-4)%12+1]
      yy = (year%2 == 0) ? "Yang" : "Yin"
      printf("%4d %-7s %-7s %s\n",year,element,animal,yy)
    }
    exit(0)
}


# Chinese zodiac

elementos = {"Wood", "Fire", "Earth", "Metal", "Water"}
animales = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"}
aspectos = {"Yang","Yin"}
tallo_celestial = {'甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'}
rama_terrestre = {'子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥'}
tallos_pinyin = {"jiă","yĭ","bĭng","dīng","wù","jĭ","gēng","xīn","rén","gŭi"}
ramas_pinyin = {"zĭ","chŏu","yín","măo","chén","sì","wŭ","wèi","shēn","yŏu","xū","hài"}
years = {1935, 1938, 1968, 1972, 1976, 1984, 2017}

For i = 0 To years[?]-1
	xYear    = years[i]
	yElemento = elementos[((xYear - 4) % 10) \ 2]
	yAnimal   = animales[  (xYear - 4) % 12     ]
	yAspectos = aspectos[   xYear      %  2     ]
	ytallo_celestial  = tallo_celestial[((xYear - 4) % 10)]
	yrama_terrestre   = rama_terrestre[  (xYear - 4) % 12 ]
	ytallos_pinyin    = tallos_pinyin[  ((xYear - 4) % 10)]
	yramas_pinyin     = ramas_pinyin[    (xYear - 4) % 12 ]
	ciclo = ((xYear - 4) % 60) + 1
	Print xYear & ": " & ytallo_celestial & yrama_terrestre & " (" & ytallos_pinyin & "-" & yramas_pinyin & ", " & yElemento & " " &  yAnimal & "; " &  yAspectos & " - ciclo " &ciclo & "/60)"
Next i
End


#include <math.h>
#include <stdio.h>

const char* animals[] = { "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig" };
const char* elements[] = { "Wood","Fire","Earth","Metal","Water" };

const char* getElement(int year) {
    int element = (int)floor((year - 4) % 10 / 2);
    return elements[element];
}

const char* getAnimal(int year) {
    return animals[(year - 4) % 12];
}

const char* getYY(int year) {
    if (year % 2 == 0) {
        return "yang";
    } else {
        return "yin";
    }
}

int main() {
    int years[] = { 1935, 1938, 1968, 1972, 1976, 2017 };
    int i;

    //the zodiac cycle didnt start until 4 CE, so years <4 shouldnt be valid
    for (i = 0; i < 6; ++i) {
        int year = years[i];
        printf("%d is the year of the %s %s (%s).\n", year, getElement(year), getAnimal(year), getYY(year));
    }

    return 0;
}


using System;

namespace ChineseZodiac {
    class Program {
        static string[] animals = { "Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig" };
        static string[] elements = { "Wood", "Fire", "Earth", "Metal", "Water" };
        static string[] animalChars = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" };
        static string[,] elementChars = { { "甲", "丙", "戊", "庚", "壬" }, { "乙", "丁", "己", "辛", "癸" } };

        static string getYY(int year) {
            if (year % 2 == 0) {
                return "yang";
            }
            return "yin";
        }

        static void Main(string[] args) {
            Console.OutputEncoding = System.Text.Encoding.UTF8;
            int[] years = { 1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017 };
            for (int i = 0; i < years.Length; i++) {
                int ei = (int)Math.Floor((years[i] - 4.0) % 10 / 2);
                int ai = (years[i] - 4) % 12;
                Console.WriteLine("{0} is the year of the {1} {2} ({3}). {4}{5}", years[i], elements[ei], animals[ai], getYY(years[i]), elementChars[years[i] % 2, ei], animalChars[(years[i] - 4) % 12]);
            }
        }
    }
}


#include <iostream>
#include <cmath>

using namespace std;

const string animals[]={"Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"};
const string elements[]={"Wood","Fire","Earth","Metal","Water"};

string getElement(int year)
{
    int element = floor((year-4)%10/2);
    return elements[element];
}

string getAnimal(int year)
{
    return animals[(year-4)%12];
}

string getYY(int year)
{
    if(year%2==0)
    {
        return "yang";
    }
    else
    {
        return "yin";
    }
}

int main()
{
    int years[]={1935,1938,1968,1972,1976,2017};
    //the zodiac cycle didnt start until 4 CE, so years <4 shouldnt be valid
    for(int i=0;i<6;i++)
    {
        cout << years[i] << " is the year of the " << getElement(years[i]) << " " << getAnimal(years[i]) << " (" << getYY(years[i]) << ")." << endl;
    }
    return 0;
}


(def base-year 4)
(def celestial-stems ["甲" "乙" "丙" "丁" "戊" "己" "庚" "辛" "壬" "癸"])
(def terrestrial-branches ["子" "丑" "寅" "卯" "辰" "巳" "午" "未" "申" "酉" "戌" "亥"])
(def zodiac-animals ["Rat" "Ox" "Tiger" "Rabbit" "Dragon" "Snake" "Horse" "Goat" "Monkey" "Rooster" "Dog" "Pig"])
(def elements ["Wood" "Fire" "Earth" "Metal" "Water"])
(def aspects ["yang" "yin"])
(def pinyin (zipmap (concat celestial-stems terrestrial-branches)
                 '("jiă" "yĭ" "bĭng" "dīng" "wù" "jĭ" "gēng" "xīn" "rén" "gŭi"
                   "zĭ" "chŏu" "yín" "măo" "chén" "sì" "wŭ" "wèi" "shēn" "yŏu" "xū" "hài")))

(defn chinese-zodiac [year]
  (let [cycle-year (- year base-year)
        cycle-position (inc (mod cycle-year 60))
        stem-number (mod cycle-year 10)
        stem-han (nth celestial-stems stem-number)
        stem-pinyin (get pinyin stem-han)
        element-number (int (Math/floor (/ stem-number 2)))
        element (nth elements element-number)
        branch-number (mod cycle-year 12)
        branch-han (nth terrestrial-branches branch-number)
        branch-pinyin (get pinyin branch-han)
        zodiac-animal (nth zodiac-animals branch-number)
        aspect-number (mod cycle-year 2)
        aspect (nth aspects aspect-number)]
    (println (format "%s: %s%s (%s-%s, %s %s; %s - cycle %s/60)"
                     year stem-han branch-han stem-pinyin branch-pinyin element zodiac-animal aspect cycle-position))))

(defn -main [& args]
  (doseq [years (map read-string args)]
    (chinese-zodiac years)))


1000 rem display the chinese zodiac for a given year
1010 poke 53281,7: rem yellow background
1020 poke 53280,2: rem red border
1030 poke 646,2: rem red text
1040 h1$="chinese zodiac":gosub 2000 set-heading
1050 gosub 3000 initialize-data
1060 print
1070 print "enter year (return to quit):";
1080 get k$:if k$="" then 1080
1090 if k$=chr$(13) then end
1100 poke 631,asc(k$):poke 198,1:rem ungetc(k$)
1110 open 1,0: input#1, y$: close 1:print
1120 if val(y$)=0 and y$<>"0" then print chr$(145):goto 1060
1130 y=val(y$)-4
1140 sy=fnym(60): rem year of the sexagesimal cycle
1150 cs=fnym(10): rem celestial stem
1160 tb=fnym(12): rem terrestrial branch
1170 el=int(cs/2): rem element
1180 za=tb: rem zodiac animal
1190 as=fnym(2): rem aspect
1200 print
1210 print "the chinese year beginning in ce "y$
1220 print "is "cs$(cs)"-"tb$(tb)", year"(sy+1)"of 60,"
1230 print "the year of the "el$(el)" "za$(za)" ("as$(as)")."
1260 goto 1060
1270 end
2000 print chr$(147);chr$(18);"****";
2010 sp=32-len(h1$)
2020 for i=1 to int(sp/2)
2030 : print " ";
2040 next i
2050 print h1$;
2060 for i=i to sp
2070 : print " ";
2080 next i
2090 print "****";
2100 return
3000 dim cs$(9): rem ten celestial stems
3010 dim tb$(11): rem twelve terrestrial branches
3020 dim za$(11): rem twelve "zodiac" animals
3030 dim el$(4): rem five elements
3040 dim as$(1): rem two aspects
3050 for i=0 to 9
3060 : read cs$(i)
3070 next i
3080 data jia3, yi3, bing3, ding1, wu4
3090 data ji3, geng1, xin1, ren2, gui3
3100 for i=0 to 11
3110 : read tb$(i)
3120 next i
3130 data zi3, chou3, yin2, mao3
3140 data chen2, si4, wu3, wei4
3150 data shen2, you3, xu1, hai4
3160 for i=0 to 11
3170 : read za$(i)
3180 next i
3190 data rat, ox, tiger, rabbit
3200 data dragon, snake, horse, goat
3210 data monkey, rooster, dog, pig
3220 for i=0 to 4
3230 : read el$(i)
3240 next i
3250 data wood, fire, earth
3260 data metal, water
3270 for i=0 to 1
3280 : read as$(i)
3290 next i
3300 data yang, yin
3310 rem year-mod function
3320 def fnym(d) = y - int(y/d)*d
3330 return


; Any CE Year that was the first of a 60-year cycle
(defconstant base-year 1984)

(defconstant celestial-stems
  '("甲" "乙" "丙" "丁" "戊" "己" "庚" "辛" "壬" "癸"))

(defconstant terrestrial-branches
  '("子" "丑" "寅" "卯" "辰" "巳" "午" "未" "申" "酉" "戌" "亥"))

(defconstant zodiac-animals
  '("Rat"   "Ox"   "Tiger"  "Rabbit"  "Dragon" "Snake"
    "Horse" "Goat" "Monkey" "Rooster" "Dog"    "Pig"))

(defconstant elements '("Wood" "Fire" "Earth" "Metal" "Water"))

(defconstant aspects '("yang" "yin"))

(defconstant pinyin
  (pairlis (append celestial-stems terrestrial-branches)
    '("jiă" "yĭ" "bĭng" "dīng" "wù" "jĭ" "gēng" "xīn" "rén" "gŭi"
      "zĭ" "chŏu" "yín" "măo" "chén" "sì" "wŭ" "wèi" "shēn" "yŏu" "xū" "hài")))

(defun this-year () (nth 5 (multiple-value-list (get-decoded-time))))

(defun pinyin-for (han) (cdr (assoc han pinyin :test #'string=)))

(defun chinese-zodiac (&rest years)
 (loop for ce-year in (if (null years) (list (this-year)) years) collecting
   (let* ((cycle-year (- ce-year base-year))
          (stem-number (mod cycle-year 10))
          (stem-han    (nth stem-number celestial-stems))
          (stem-pinyin (pinyin-for stem-han))

          (element-number (floor stem-number 2))
          (element        (nth element-number elements))

          (branch-number (mod cycle-year 12))
          (branch-han    (nth branch-number terrestrial-branches))
          (branch-pinyin (pinyin-for branch-han))
          (zodiac-animal (nth branch-number zodiac-animals))

          (aspect-number (mod cycle-year 2))
          (aspect        (nth aspect-number aspects)))
          (cons ce-year (list stem-han branch-han stem-pinyin branch-pinyin element zodiac-animal aspect)))))

(defun get-args ()
  (or
   #+CLISP *args*
   #+SBCL (cdr *posix-argv*)
   #+LISPWORKS system:*line-arguments-list*
   #+CMU extensions:*command-line-words*
   nil))

(loop for cz in (apply #'chinese-zodiac (mapcar #'read-from-string (get-args)))
 doing
  (format t "~{~a: ~a~a (~a-~a, ~a ~a; ~a)~%~}" cz))


import std.stdio;

// 10 heavenly stems
immutable tiangan=[
    ["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"],
    ["jiă","yĭ","bĭng","dīng","wù","jĭ","gēng","xīn","rén","gŭi"]
];

// 12 terrestrial branches
immutable dizhi=[
    ["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"],
    ["zĭ","chŏu","yín","măo","chén","sì","wŭ","wèi","shēn","yŏu","xū","hài"]
];

// 5 elements
immutable wuxing=[
    ["木","火","土","金","水"],
    ["mù","huǒ","tǔ","jīn","shuǐ"],
    ["wood","fire","earth","metal","water"]
];

// 12 symbolic animals
immutable shengxiao=[
    ["鼠","牛","虎","兔","龍","蛇","馬","羊","猴","鸡","狗","豬"],
    ["shǔ","niú","hǔ","tù","lóng","shé","mǎ","yáng","hóu","jī","gǒu","zhū"],
    ["rat","ox","tiger","rabbit","dragon","snake","horse","goat","monkey","rooster","dog","pig"]
];

// yin yang
immutable yinyang=[
    ["阳","阴"],
    ["yáng","yīn"]
];

void main(string[] args) {
    process(args[1..$]);
}

void process(string[] years) {
    import std.conv;
    foreach(yearStr; years) {
        try {
            auto year = to!int(yearStr);

            auto cy = year - 4;
            auto stem = cy % 10;
            auto branch = cy % 12;

            writefln("%4s  %-11s  %-7s  %-10s%s", year,tiangan[0][stem]~dizhi[0][branch], wuxing[0][stem/2], shengxiao[0][branch], yinyang[0][year%2]);
            writefln("      %-12s%-8s%-10s%s",      tiangan[1][stem]~dizhi[1][branch],    wuxing[1][stem/2], shengxiao[1][branch], yinyang[1][year%2]);
            writefln("      %2s/60     %-7s%s", cy%60+1,                                  wuxing[2][stem/2], shengxiao[2][branch]);
            writeln;
        } catch (ConvException e) {
            stderr.writeln("Not a valid year: ", yearStr);
        }
    }
}


program Chinese_zodiac;

{$APPTYPE CONSOLE}

uses
  Winapi.Windows,
  System.SysUtils,
  System.Math;

type
  TElements = array of array of char;

  TChineseZodiac = record
    Year: Integer;
    Yyear: string;
    Animal: string;
    Element: string;
    AnimalChar: char;
    ElementChar: char;
    procedure Assign(aYear: Integer);
    function ToString: string;
  end;

const
  animals: TArray<string> = ['Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake',
    'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig'];
  elements: TArray<string> = ['Wood', 'Fire', 'Earth', 'Metal', 'Water'];
  animalChars: TArray<char> = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉',
    '戌', '亥'];
  elementChars: TElements = [['甲', '丙', '戊', '庚', '壬'], ['乙', '丁', '己', '辛', '癸']];

function getYY(year: Integer): string;
begin
  if (year mod 2) = 0 then
  begin
    Exit('yang');
  end;
  Exit('yin');
end;

{ TChineseZodiac }

procedure TChineseZodiac.Assign(aYear: Integer);
var
  ei, ai: Integer;
begin
  ei := Trunc(Floor((Trunc(aYear - 4.0) mod 10) / 2));
  ai := (aYear - 4) mod 12;
  year := aYear;
  Element := elements[ei];
  Animal := animals[ai];
  ElementChar := elementChars[aYear mod 2, ei];
  AnimalChar := animalChars[(aYear - 4) mod 12];
  Yyear := getYY(aYear);
end;

var
  z: TChineseZodiac;
  years: TArray<Integer> = [1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017];
  year: integer;

function TChineseZodiac.ToString: string;
begin
  Result := Format('%d is the year of the %s %s (%s). %s%s', [year, Element,
    Animal, Yyear, ElementChar, AnimalChar]);
end;

var
  Outfile: TextFile;
  Written: Cardinal;

begin
  SetConsoleOutputCP(CP_UTF8);

  AssignFile(Outfile, 'Output.txt', CP_UTF8);
  Rewrite(Outfile);

  for year in years do
  begin
    z.Assign(year);
    Writeln(Outfile, z.ToString);
    Writeln(z.ToString);
  end;

  CloseFile(Outfile);
  Readln;
end.


CNZODIAC
=LAMBDA(y,
    APPENDCOLS(
        APPENDCOLS(
            APPENDCOLS(
                CNYEARNAME(y)
            )(
                CNYEARELEMENT(y)
            )
        )(
            CNYEARANIMAL(y)
        )
    )(
        CNYEARYINYANG(y)
    )
)

CNYEARANIMAL
=LAMBDA(y,
    LET(
        shengxiao, {
         "鼠","shǔ","rat";
         "牛","niú","ox";
         "虎","hǔ","tiger";
         "兔","tù","rabbit";
         "龍","lóng","dragon";
         "蛇","shé","snake";
         "馬","mǎ","horse";
         "羊","yáng","goat";
         "猴","hóu","monkey";
         "鸡","jī","rooster";
         "狗","gǒu","dog";
         "豬","zhū","pig"
         },

        iYear, y - 4,
        iBranch, 1 + MOD(iYear, 12),

        TRANSPOSE(
            INDEX(shengxiao, iBranch)
        )
    )
)

CNYEARELEMENT
=LAMBDA(y,
    LET(
        wuxing, {
         "木","mù","wood";
         "火","huǒ","fire";
         "土","tǔ","earth";
         "金","jīn","metal";
         "水","shuǐ","water"
         },

        iYear, y - 4,
        iStem, MOD(iYear, 10),

        TRANSPOSE(
            INDEX(
                wuxing,
                1 + QUOTIENT(
                    iStem,
                    2
                )
            )
        )
    )
)

CNYEARNAME
=LAMBDA(y,
    LET(
        tiangan, {
         "甲","jiă";
         "乙","yĭ";
         "丙","bĭng";
         "丁","dīng";
         "戊","wù";
         "己","jĭ";
         "庚","gēng";
         "辛","xīn";
         "壬","rén";
         "癸","gŭi"
         },

         dizhi, {
         "子","zĭ";
         "丑","chŏu";
         "寅","yín";
         "卯","măo";
         "辰","chén";
         "巳","sì";
         "午","wŭ";
         "未","wèi";
         "申","shēn";
         "酉","yŏu";
         "戌","xū";
         "亥","hài"
         },

        iYear, y - 4,
        iStem, 1 + MOD(iYear, 10),
        iBranch, 1 + MOD(iYear, 12),
        iIndex, 1 + MOD(iYear, 60),

        stem, INDEX(tiangan, iStem),
        branch, INDEX(dizhi, iBranch),

        APPENDROWS(
            APPENDROWS(
                CONCAT(INDEX(stem, 1), INDEX(branch, 1))
            )(
                CONCAT(INDEX(stem, 2), INDEX(branch, 2))
            )
        )(iIndex & "/60")
    )
)

CNYEARYINYANG
=LAMBDA(y,
    LET(
        yinyang, {
         "阳","yáng", "bright";
         "阴","yīn", "dark"
         },

        TRANSPOSE(
            INDEX(
                yinyang,
                1 + MOD(y - 4, 2)
            )
        )
    )
)


open System

let animals = ["Rat";"Ox";"Tiger";"Rabbit";"Dragon";"Snake";"Horse";"Goat";"Monkey";"Rooster";"Dog";"Pig"]
let elements = ["Wood";"Fire";"Earth";"Metal";"Water"]
let years = [1935;1938;1968;1972;1976;1984;1985;2017]

let getZodiac(year: int) =
    let animal = animals.Item((year-4)%12)
    let element = elements.Item(((year-4)%10)/2)
    let yy = if year%2 = 0 then "(Yang)" else "(Yin)"

    String.Format("{0} is the year of the {1} {2} {3}", year, element, animal, yy)

[<EntryPoint>]
let main argv =
    let mutable string = ""
    for i in years do
        string <- getZodiac(i)
        printf "%s" string
        Console.ReadLine() |> ignore
    0 // return an integer exit code


USING: circular formatting io kernel math qw sequences
sequences.repeating ;
IN: rosetta-code.zodiac

<PRIVATE

! Offset start index by -4 because first cycle started on 4 CE.
: circularize ( seq -- obj )
    [ -4 ] dip <circular> [ change-circular-start ] keep ;

: animals ( -- obj )
    qw{
        Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey
        Rooster Dog Pig
    } circularize ;

: elements ( -- obj )
    qw{ Wood Fire Earth Metal Water } 2 <repeats> circularize ;

PRIVATE>

: zodiac ( n -- str )
    dup [ elements nth ] [ animals nth ]
    [ even? "yang" "yin" ? ] tri
    "%d is the year of the %s %s (%s)." sprintf ;

: zodiac-demo ( -- )
    { 1935 1938 1968 1972 1976 1984 1985 2017 }
    [ zodiac print ] each ;

MAIN: zodiac-demo


dim as string yy(0 to 1) = {"yang", "yin"}
dim as string elements(0 to 4) = {"Wood", "Fire", "Earth", "Metal", "Water"}
dim as string animals(0 to 11) = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",_
                                  "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"}

dim as uinteger yr, y, e, a, i, tests(0 to 5) = {1801, 1861, 1984, 2020, 2186, 76543}
dim as string outstr

for i = 0 to 5
   yr = tests(i)
   y = yr mod 2
   e = (yr - 4) mod 5
   a = (yr - 4) mod 12
   outstr = str(yr)+" is the year of the "
   outstr += elements(e)+" " + animals(a) + " (" + yy(y) + ")."

   print outstr
next i


package main

import "fmt"

var (
    animalString = []string{"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
        "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"}
    stemYYString  = []string{"Yang", "Yin"}
    elementString = []string{"Wood", "Fire", "Earth", "Metal", "Water"}
    stemCh        = []rune("甲乙丙丁戊己庚辛壬癸")
    branchCh      = []rune("子丑寅卯辰巳午未申酉戌亥")
)

func cz(yr int) (animal, yinYang, element, stemBranch string, cycleYear int) {
    yr -= 4
    stem := yr % 10
    branch := yr % 12
    return animalString[branch],
        stemYYString[stem%2],
        elementString[stem/2],
        string([]rune{stemCh[stem], branchCh[branch]}),
        yr%60 + 1
}

func main() {
    for _, yr := range []int{1935, 1938, 1968, 1972, 1976} {
        a, yy, e, sb, cy := cz(yr)
        fmt.Printf("%d: %s %s, %s, Cycle year %d %s\n",
            yr, e, a, yy, cy, sb)
    }
}


class Zodiac {
    final static String[] animals = ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"]
    final static String[] elements = ["Wood", "Fire", "Earth", "Metal", "Water"]
    final static String[] animalChars = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
    static String[][] elementChars = [["甲", "丙", "戊", "庚", "壬"], ["乙", "丁", "己", "辛", "癸"]]

    static String getYY(int year) {
        if (year % 2 == 0) {
            return "yang"
        } else {
            return "yin"
        }
    }

    static void main(String[] args) {
        int[] years = [1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017]
        for (int i = 0; i < years.length; i++) {
            println(years[i] + " is the year of the " + elements[(int) Math.floor((years[i] - 4) % 10 / 2)] + " " + animals[(years[i] - 4) % 12] + " (" + getYY(years[i]) + "). " + elementChars[years[i] % 2][(int) Math.floor((years[i] - 4) % 10 / 2)] + animalChars[(years[i] - 4) % 12])
        }
    }
}


import Data.Array (Array, listArray, (!))

------------------- TRADITIONAL STRINGS ------------------
ats :: Array Int (Char, String)
ats =
  listArray (0, 9) $
    zip
      -- 天干 tiangan – 10 heavenly stems
      "甲乙丙丁戊己庚辛壬癸"
      (words "jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi")

ads :: Array Int (String, String)
ads =
  listArray (0, 11) $
    zip
      -- 地支 dizhi – 12 terrestrial branches
      (chars "子丑寅卯辰巳午未申酉戌亥")
      ( words $
          "zĭ chŏu yín măo chén sì "
            <> "wŭ wèi shēn yŏu xū hài"
      )

aws :: Array Int (String, String, String)
aws =
  listArray (0, 4) $
    zip3
      -- 五行 wuxing – 5 elements
      (chars "木火土金水")
      (words "mù huǒ tǔ jīn shuǐ")
      (words "wood fire earth metal water")

axs :: Array Int (String, String, String)
axs =
  listArray (0, 11) $
    zip3
      -- 十二生肖 shengxiao – 12 symbolic animals
      (chars "鼠牛虎兔龍蛇馬羊猴鸡狗豬")
      ( words $
          "shǔ niú hǔ tù lóng shé "
            <> "mǎ yáng hóu jī gǒu zhū"
      )
      ( words $
          "rat ox tiger rabbit dragon snake "
            <> "horse goat monkey rooster dog pig"
      )

ays :: Array Int (String, String)
-- 阴阳 yinyang
ays =
  listArray (0, 1) $
    zip (chars "阳阴") (words "yáng yīn")

chars :: String -> [String]
chars = (flip (:) [] <$>)

-------------------- TRADITIONAL CYCLES ------------------
f生肖五行年份 y =
  let i年份 = y - 4
      i天干 = rem i年份 10
      i地支 = rem i年份 12
      (h天干, p天干) = ats ! i天干
      (h地支, p地支) = ads ! i地支
      (h五行, p五行, e五行) = aws ! quot i天干 2
      (h生肖, p生肖, e生肖) = axs ! i地支
      (h阴阳, p阴阳) = ays ! rem i年份 2
   in -- 汉子 Chinese characters
      [ [show y, h天干 : h地支, h五行, h生肖, h阴阳],
        -- Pinyin roman transcription
        [[], p天干 <> p地支, p五行, p生肖, p阴阳],
        -- English
        [ [],
          show (rem i年份 60 + 1) <> "/60",
          e五行,
          e生肖,
          []
        ]
      ]

--------------------------- TEST -------------------------
main :: IO ()
main =
  mapM_ putStrLn $
    showYear
      <$> [1935, 1938, 1968, 1972, 1976, 1984, 2017]

------------------------ FORMATTING ----------------------
fieldWidths :: [[Int]]
fieldWidths =
  [ [6, 10, 7, 8, 3],
    [6, 11, 8, 8, 4],
    [6, 11, 8, 8, 4]
  ]

showYear :: Int -> String
showYear y =
  unlines $
    ( \(ns, xs) ->
        concat $
          uncurry (`justifyLeft` ' ')
            <$> zip ns xs
    )
      <$> zip fieldWidths (f生肖五行年份 y)
  where
    justifyLeft n c s = take n (s <> replicate n c)


   ELEMENTS=: _4 |. 2 # ;:'Wood Fire Earth Metal Water'
   YEARS=: 1935 1938 1968 1972 1976 2017

   ANIMALS=: _4 |. ;:'Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig'
   YINYANG=: ;:'yang yin'

   cz=: (|~ #)~ { [

   ANIMALS cz YEARS
┌───┬─────┬──────┬───┬──────┬───────┐
│Pig│Tiger│Monkey│Rat│Dragon│Rooster│
└───┴─────┴──────┴───┴──────┴───────┘

   YINYANG cz YEARS
┌───┬────┬────┬────┬────┬───┐
│yin│yang│yang│yang│yang│yin│
└───┴────┴────┴────┴────┴───┘

   chinese_zodiac =: 3 : ';:inv(<":y),(ELEMENTS cz y),(ANIMALS cz y),(<''(''),(YINYANG cz y),(<'')'')'

   chinese_zodiac&>YEARS
1935 Wood Pig ( yin )
1938 Earth Tiger ( yang )
1968 Earth Monkey ( yang )
1972 Water Rat ( yang )
1976 Fire Dragon ( yang )
2017 Fire Rooster ( yin )

   'CELESTIAL TERRESTRIAL'=:7&u:&.>{&a.&.> 16be7 16b94 16bb2 16be4 16bb9 16b99 16be4 16bb8 16b99 16be4 16bb8 16b81 16be6 16b88 16b8a 16be5 16bb7 16bb1 16be5 16bba 16b9a 16be8 16bbe 16b9b 16be5 16ba3 16bac 16be7 16b99 16bb8; 16be5 16bad 16b90 16be4 16bb8 16b91 16be5 16baf 16b85 16be5 16b8d 16baf 16be8 16bbe 16bb0 16be5 16bb7 16bb3 16be5 16b8d 16b88 16be6 16b9c 16baa 16be7 16b94 16bb3 16be9 16b85 16b89 16be6 16b88 16b8c 16be4 16bba 16ba5

   ANIMALS=: ;/ _4 |. TERRESTRIAL
   ELEMENTS=: ;/ _4 |. CELESTIAL

   chinese_zodiac&>YEARS
1935 乙 亥 ( yin )
1938 戊 寅 ( yang )
1968 戊 申 ( yang )
1972 壬 子 ( yang )
1976 丙 辰 ( yang )
2017 丁 酉 ( yin )


public class Zodiac {

	final static String animals[]={"Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"};
	final static String elements[]={"Wood","Fire","Earth","Metal","Water"};
	final static String animalChars[]={"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
	static String elementChars[][]={{"甲","丙","戊","庚","壬"},{"乙","丁","己","辛","癸"}};

	static String getYY(int year)
	{
	    if(year%2==0)
	    {
	        return "yang";
	    }
	    else
	    {
	        return "yin";
	    }
	}

	public static void main(String[] args)
	{
		int years[]={1935,1938,1968,1972,1976,1984,1985,2017};
		for(int i=0;i<years.length;i++)
		{
			System.out.println(years[i]+" is the year of the "+elements[(int) Math.floor((years[i]-4)%10/2)]+" "+animals[(years[i]-4)%12]+" ("+getYY(years[i])+"). "+elementChars[years[i]%2][(int) Math.floor((years[i]-4)%10/2)]+animalChars[(years[i]-4)%12]);
		}
	}
}


(() => {
    "use strict";

    // ---------- TRADITIONAL CALENDAR STRINGS -----------

    // ats :: Array Int (String, String)
    const ats = () =>
        // 天干 tiangan – 10 heavenly stems
        zip(
            chars("甲乙丙丁戊己庚辛壬癸")
        )(
            words("jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi")
        );

    // ads :: Array Int (String, String)
    const ads = () =>
        // 地支 dizhi – 12 terrestrial branches
        zip(
            chars("子丑寅卯辰巳午未申酉戌亥")
        )(
            words(
                "zĭ chŏu yín măo chén sì " + (
                    "wŭ wèi shēn yŏu xū hài"
                )
            )
        );

    // aws :: Array Int (String, String, String)
    const aws = () =>
        // 五行 wuxing – 5 elements
        zip3(
            chars("木火土金水")
        )(
            words("mù huǒ tǔ jīn shuǐ")
        )(
            words("wood fire earth metal water")
        );

    // axs :: Array Int (String, String, String)
    const axs = () =>
        // 十二生肖 shengxiao – 12 symbolic animals
        zip3(
            chars("鼠牛虎兔龍蛇馬羊猴鸡狗豬")
        )(
            words(
                "shǔ niú hǔ tù lóng shé " + (
                    "mǎ yáng hóu jī gǒu zhū"
                )
            )
        )(
            words(
                "rat ox tiger rabbit dragon snake " + (
                    "horse goat monkey rooster dog pig"
                )
            )
        );

    // ays :: Array Int (String, String)
    const ays = () =>
        // 阴阳 yinyang
        zip(
            chars("阳阴")
        )(
            words("yáng yīn")
        );

    // --------------- TRADITIONAL CYCLES ----------------
    const zodiac = y => {
        const
            iYear = y - 4,
            iStem = iYear % 10,
            iBranch = iYear % 12,
            [hStem, pStem] = ats()[iStem],
            [hBranch, pBranch] = ads()[iBranch],
            [hElem, pElem, eElem] = aws()[quot(iStem)(2)],
            [hAnimal, pAnimal, eAnimal] = axs()[iBranch],
            [hYinyang, pYinyang] = ays()[iYear % 2];

        return [
            [
                show(y), hStem + hBranch, hElem,
                hAnimal, hYinyang
            ],
            ["", pStem + pBranch, pElem, pAnimal, pYinyang],
            [
                "", `${show((iYear % 60) + 1)}/60`,
                eElem, eAnimal, ""
            ]
        ];
    };

    // ---------------------- TEST -----------------------
    const main = () => [
            1935, 1938, 1968, 1972, 1976, 1984,
            new Date().getFullYear()
        ]
        .map(showYear)
        .join("\n\n");

    // ------------------- FORMATTING --------------------
    // fieldWidths :: [[Int]]
    const fieldWidths = [
        [6, 10, 7, 8, 3],
        [6, 11, 8, 8, 4],
        [6, 11, 8, 8, 4]
    ];

    // showYear :: Int -> String
    const showYear = y =>
        zipWith(zip)(fieldWidths)(zodiac(y))
        .map(
            row => row.map(
                ([n, s]) => s.padEnd(n, " ")
            )
            .join("")
        )
        .join("\n");

    // ---------------- GENERIC FUNCTIONS ----------------

    // chars :: String -> [Char]
    const chars = s => [...s];

    // quot :: Integral a => a -> a -> a
    const quot = n =>
        m => Math.trunc(n / m);

    // show :: Int -> a -> Indented String
    // show :: a -> String
    const show = (...x) =>
        JSON.stringify.apply(
            null, x.length > 1 ? [
                x[1], null, x[0]
            ] : x
        );

    // words :: String -> [String]
    const words = s =>
        // List of space-delimited sub-strings.
        s.split(/\s+/u);

    // zip :: [a] -> [b] -> [(a, b)]
    const zip = xs =>
        // The paired members of xs and ys, up to
        // the length of the shorter of the two lists.
        ys => Array.from({
            length: Math.min(xs.length, ys.length)
        }, (_, i) => [xs[i], ys[i]]);

    // zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
    const zip3 = xs =>
        ys => zs => xs.slice(
            0,
            Math.min(...[xs, ys, zs].map(x => x.length))
        )
        .map((x, i) => [x, ys[i], zs[i]]);

    // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    const zipWith = f =>
        // A list constructed by zipping with a
        // custom function, rather than with the
        // default tuple constructor.
        xs => ys => xs.map(
            (x, i) => f(x)(ys[i])
        ).slice(
            0, Math.min(xs.length, ys.length)
        );

    // MAIN ---
    return main();
})();


function chinese(year::Int)
    pinyin = Dict(
        "甲" => "jiă",
        "乙" => "yĭ",
        "丙" => "bĭng",
        "丁" => "dīng",
        "戊" => "wù",
        "己" => "jĭ",
        "庚" => "gēng",
        "辛" => "xīn",
        "壬" => "rén",
        "癸" => "gŭi",
        "子" => "zĭ",
        "丑" => "chŏu",
        "寅" => "yín",
        "卯" => "măo",
        "辰" => "chén",
        "巳" => "sì",
        "午" => "wŭ",
        "未" => "wèi",
        "申" => "shēn",
        "酉" => "yŏu",
        "戌" => "xū",
        "亥" => "hài",
    )
    elements    = ["Wood", "Fire", "Earth", "Metal", "Water"]
    animals     = ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
                   "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"]
    celestial   = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]
    terrestrial = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
    aspects     = ["yang", "yin"]
    base = 4

    cycleyear = year - base

    stemnumber = cycleyear % 10 + 1
    stemhan    = celestial[stemnumber]
    stempinyin = pinyin[stemhan]

    elementnumber = div(stemnumber, 2) + 1
    element       = elements[elementnumber]

    branchnumber = cycleyear % 12 + 1
    branchhan    = terrestrial[branchnumber]
    branchpinyin = pinyin[branchhan]
    animal       = animals[branchnumber]

    aspectnumber = cycleyear % 2 + 1
    aspect       = aspects[aspectnumber]

    index = cycleyear % 60 + 1

    return "$year: $stemhan$branchhan ($stempinyin-$branchpinyin, $element $animal; $aspect - year $index of the cycle)"
end

curryr = Dates.year(now())
yrs = [1935, 1938, 1968, 1972, 1976, curryr]
foreach(println, map(chinese, yrs))


// version 1.1.2

class ChineseZodiac(val year: Int) {
    val stem   : Char
    val branch : Char
    val sName  : String
    val bName  : String
    val element: String
    val animal : String
    val aspect : String
    val cycle  : Int

    private companion object {
        val animals  = listOf("Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
                              "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig")
        val aspects  = listOf("Yang","Yin")
        val elements = listOf("Wood", "Fire", "Earth", "Metal", "Water")
        val stems    = listOf('甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸')
        val branches = listOf('子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥')
        val sNames   = listOf("jiă", "yĭ", "bĭng", "dīng", "wù", "jĭ", "gēng", "xīn", "rén", "gŭi")
        val bNames   = listOf("zĭ", "chŏu", "yín", "măo", "chén", "sì", "wŭ", "wèi", "shēn", "yŏu",  "xū", "hài")
        val fmt      = "%d    %c%c   %-9s  %-7s  %-7s   %-6s %02d/60"
    }

    init {
        val y = year - 4
        val s = y % 10
        val b = y % 12
        stem    = stems[s]
        branch  = branches[b]
        sName   = sNames[s]
        bName   = bNames[b]
        element = elements[s / 2]
        animal  = animals[b]
        aspect  = aspects[s % 2]
        cycle   = y % 60 + 1
    }

    override fun toString() =
        fmt.format(year, stem, branch, sName + "-" + bName, element, animal, aspect, cycle)
}

fun main(args: Array<String>) {
    val years = intArrayOf(1935, 1938, 1968, 1972, 1976, 1984, 2017)
    println("Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle")
    println("----  -------  ---------  -------  -------  ------  -----")
    for (year in years) println(ChineseZodiac(year))
}


local ANIMALS = {"Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"}
local ELEMENTS = {"Wood","Fire","Earth","Metal","Water"}

function element(year)
    local idx = math.floor(((year - 4) % 10) / 2)
    return ELEMENTS[idx + 1]
end

function animal(year)
    local idx = (year - 4) % 12
    return ANIMALS[idx + 1]
end

function yy(year)
    if year % 2 == 0 then
        return "yang"
    else
        return "yin"
    end
end

function zodiac(year)
    local e = element(year)
    local a = animal(year)
    local y = yy(year)
    print(year.." is the year of the "..e.." "..a.." ("..y..")")
end

zodiac(1935)
zodiac(1938)
zodiac(1968)
zodiac(1972)
zodiac(1976)
zodiac(2017)


zodiac:=proc(year::integer)
	local year60,yinyang,animal,element;
	year60:= (year-3) mod 60;
	yinyang:=["Yin","Yang"];
	animal:=["Pig","Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog"];
	element:=["Water","Wood","Wood","Fire","Fire","Earth","Earth","Metal","Metal","Water"];
	return sprintf("%a",cat(year," is the year of the ",element[(year60 mod 10)+1]," ",animal[(year60 mod 12)+1]," (",yinyang[(year60 mod 2)+1],")"));
end proc:


pinyin = <|"甲" -> "jiă", "乙" -> "yĭ", "丙" -> "bĭng", "丁" -> "dīng",
   "戊" -> "wù", "己" -> "jĭ", "庚" -> "gēng", "辛" -> "xīn",
   "壬" -> "rén", "癸" -> "gŭi", "子" -> "zĭ", "丑" -> "chŏu",
   "寅" -> "yín", "卯" -> "măo", "辰" -> "chén", "巳" -> "sì",
   "午" -> "wŭ", "未" -> "wèi", "申" -> "shēn", "酉" -> "yŏu",
   "戌" -> "xū", "亥" -> "hài"|>;
animals = {"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse",
    "Goat", "Monkey", "Rooster", "Dog", "Pig"};
elements = {"Wood", "Fire", "Earth", "Metal", "Water"};
celestial = {"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"};
terrestrial = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌",
   "亥"};
aspects = {"yang", "yin"};
ClearAll[calculate]
calculate[year_] := Module[{BASE, cycleyear, stemnumber, stempinyin, element,
   elementnumber, branchnumber, branchhan, branchpinyin, animal,
   aspectnumber, aspect, stemhan},
  BASE = 4;
  cycleyear = year - BASE;
  stemnumber = Mod[cycleyear + 1, 10, 1];
  stemhan = celestial[[stemnumber]];
  stempinyin = pinyin[[stemhan]];
  elementnumber = Floor[stemnumber/2 + 1/2];
  element = elements[[elementnumber]];
  branchnumber = Mod[cycleyear + 1, 12, 1];
  branchhan = terrestrial[[branchnumber]];
  branchpinyin = pinyin[[branchhan]];
  animal = animals[[branchnumber]];
  aspectnumber = Mod[cycleyear + 1, 2, 1];
  aspect = aspects[[aspectnumber]];
  [email protected]{year, ": ", stemhan, branchhan, " (", stempinyin, "-", branchpinyin, ", ", element, " ", animal, "; ", aspect, ")"}
  ]
calculate[1935]
calculate[1938]
calculate[1941]
calculate[1947]
calculate[1968]
calculate[1972]
calculate[1976]


MODULE ChineseZodiac;
FROM FormatString IMPORT FormatString;
FROM Terminal IMPORT WriteString,ReadChar;

TYPE Str = ARRAY[0..7] OF CHAR;

TYPE AA = ARRAY[0..11] OF Str;
CONST ANIMALS = AA{"Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"};

TYPE EA = ARRAY[0..4] OF Str;
CONST ELEMENTS = EA{"Wood","Fire","Earth","Metal","Water"};

PROCEDURE element(year : INTEGER) : Str;
VAR idx : CARDINAL;
BEGIN
    idx := ((year - 4) MOD 10) / 2;
    RETURN ELEMENTS[idx];
END element;

PROCEDURE animal(year : INTEGER) : Str;
VAR idx : CARDINAL;
BEGIN
    idx := (year - 4) MOD 12;
    RETURN ANIMALS[idx];
END animal;

PROCEDURE yy(year : INTEGER) : Str;
BEGIN
    IF year MOD 2 = 0 THEN
        RETURN "yang"
    ELSE
        RETURN "yin"
    END
END yy;

PROCEDURE print(year : INTEGER);
VAR buf : ARRAY[0..63] OF CHAR;
BEGIN
    FormatString("%i is the year of the %s %s (%s)\n", buf, year, element(year), animal(year), yy(year));
    WriteString(buf);
END print;

(* main *)
BEGIN
    print(1935);
    print(1938);
    print(1968);
    print(1972);
    print(1976);
    print(2017);

    ReadChar
END ChineseZodiac.


import strformat

const ANIMALS: array[12, string] = ["Rat",    "Ox",
                                    "Tiger",  "Rabbit",
                                    "Dragon", "Snake",
                                    "Horse",  "Goat",
                                    "Monkey", "Rooster",
                                    "Dog",    "Pig"]

const ASPECTS: array[2, string] = ["Yang",   "Yin"]

const ELEMENTS: array[5, string] = ["Wood",  "Fire",
                                    "Earth", "Metal",
                                    "Water"]

const STEMS: array[10, string] = ["甲", "乙", "丙", "丁", "戊",
                                  "己", "庚", "辛", "壬", "癸"]

const BRANCHES: array[12, string] = ["子", "丑", "寅", "卯", "辰", "巳",
                                     "午", "未", "申", "酉", "戌", "亥"]

const S_NAMES: array[10, string] = ["jiă", "yĭ", "bĭng", "dīng", "wù",
                                    "jĭ", "gēng", "xīn", "rén", "gŭi"]

const B_NAMES: array[12, string] = ["zĭ", "chŏu", "yín", "măo", "chén", "sì",
                                    "wŭ", "wèi", "shēn", "yŏu", "xū", "hài"]

proc chineseZodiac(year: int): string =
  let y = year - 4
  let s = y mod 10
  let b = y mod 12
  let stem = STEMS[s]
  let branch = BRANCHES[b]
  let name = S_NAMES[s] & "-" & B_NAMES[b]
  let element = ELEMENTS[s div 2]
  let animal = ANIMALS[b]
  let aspect = ASPECTS[s mod 2]
  let cycle = y mod 60 + 1
  &"{year}   {stem}{branch}     {name:9}  {element:7}  {animal:7}  {aspect:6}  {cycle:02}/60"

let years = [1935, 1938, 1968, 1972, 1976, 1984, 2017, 2020]
echo "Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle"
echo "----  -------  ------     -------  ------   ------  -----"
for year in years:
  echo &"{chineseZodiac(year)}"


type
	animalCycle = (rat, ox, tiger, rabbit, dragon, snake,
		horse, goat, monkey, rooster, dog, pig);
	elementCycle = (wood, fire, earth, metal, water);
	aspectCycle = (yang, yin);

	zodiac = record
			animal: animalCycle;
			element: elementCycle;
			aspect: aspectCycle;
		end;

function getZodiac(year: integer): zodiac;
begin
	year := pred(year, 4);
	getZodiac := zodiac[
			animal: succ(rat, year mod 12);
			element: succ(wood, year mod 10 div 2);
			aspect: succ(yang, year mod 2);
		]
end;


sub zodiac {
  my $year = shift;
  my @animals = qw/Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig/;
  my @elements = qw/Wood Fire Earth Metal Water/;
  my @terrestrial_han = qw/子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥/;
  my @terrestrial_pinyin = qw/zĭ chŏu yín măo chén sì wŭ wèi shēn yŏu xū hài/;
  my @celestial_han = qw/甲 乙 丙 丁 戊 己 庚 辛 壬 癸/;
  my @celestial_pinyin = qw/jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi/;
  my @aspect = qw/yang yin/;

  my $cycle_year = ($year-4) % 60;
  my($i2, $i10, $i12) = ($cycle_year % 2, $cycle_year % 10, $cycle_year % 12);

  ($year,
   $celestial_han[$i10], $terrestrial_han[$i12],
   $celestial_pinyin[$i10], $terrestrial_pinyin[$i12],
   $elements[$i10 >> 1], $animals[$i12], $aspect[$i2], $cycle_year+1);
}

printf("%4d: %s%s (%s-%s) %s %s; %s - year %d of the cycle\n", zodiac($_))
  for (1935, 1938, 1968, 1972, 1976, 2017);


with javascript_semantics
constant animals = {"Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"},
         elements = {"Wood","Fire","Earth","Metal","Water"},
         yinyang = {"yang","yin"},
         years = {1935,1938,1968,1972,1976,2018}

for i=1 to length(years) do
    integer year = years[i],
            cycle = mod(year-4,60)
    string element = elements[floor(mod(cycle,10)/2)+1],
           animal = animals[mod(cycle,12)+1],
           yy = yinyang[mod(cycle,2)+1]
    printf(1,"%d: %s %s; %s, year %d of the cycle.\n",
             {year,element,animal,yy,cycle+1})
end for


animals({"Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"}).

elements({"Wood", "Fire", "Earth", "Metal", "Water"}).

animal_chars({"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"}).

element_chars({{"甲", "丙", "戊", "庚", "壬"}, {"乙", "丁", "己", "辛", "癸"}}).

years({1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017}).

year_animal(Year) = Animal =>
    I = ((Year - 4) mod 12) + 1,
    animals(Animals),
    Animal = Animals[I].

year_element(Year) = Element =>
    I = ((Year - 4) mod 10) div 2 + 1,
    elements(Elements),
    Element = Elements[I].

year_animal_char(Year) = AnimalChar =>
    I = (Year - 4) mod 12 + 1,
    animal_chars(AnimalChars),
    AnimalChar = AnimalChars[I].

year_element_char(Year) = ElementChar =>
    I1 = Year mod 2 + 1,
    element_chars(ElementChars),
    ElementChars1 = ElementChars[I1],
    I2 = (Year - 4) mod 10 div 2 + 1,
    ElementChar = ElementChars1[I2].

year_yin_yang(Year) = YinYang =>
    Year mod 2 == 0 -> YinYang = "yang" ; YinYang = "yin".

main :-
    years(Years),
    foreach (Year in Years)
        Element = year_element(Year),
        Animal = year_animal(Year),
        YinYang = year_yin_yang(Year),
        ElementChar = year_element_char(Year),
        AnimalChar = year_animal_char(Year),
        printf("%d is the year of the %w %w (%w). %w%w\n", Year, Element, Animal, YinYang, ElementChar, AnimalChar)
    end.


function Get-ChineseZodiac
{
    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    Param
    (
        [Parameter(Mandatory=$false,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [ValidateRange(1,9999)]
        [int]
        $Year = (Get-Date).Year
    )

    Begin
    {
        $pinyin = @{
            '甲' = 'jiă'
            '乙' = 'yĭ'
            '丙' = 'bĭng'
            '丁' = 'dīng'
            '戊' = 'wù'
            '己' = 'jĭ'
            '庚' = 'gēng'
            '辛' = 'xīn'
            '壬' = 'rén'
            '癸' = 'gŭi'
            '子' = 'zĭ'
            '丑' = 'chŏu'
            '寅' = 'yín'
            '卯' = 'măo'
            '辰' = 'chén'
            '巳' = 'sì'
            '午' = 'wŭ'
            '未' = 'wèi'
            '申' = 'shēn'
            '酉' = 'yŏu'
            '戌' = 'xū'
            '亥' = 'hài'
        }

        $celestial   = '甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'
        $terrestrial = '子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'
        $animals     = 'Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake', 'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig'
        $elements    = 'Wood', 'Fire', 'Earth', 'Metal', 'Water'
        $aspects     = 'yang', 'yin'

        $base = 4
    }
    Process
    {
        foreach ($ce_year in $Year)
        {
            $cycle_year     = $ce_year - $base

            $stem_number    = $cycle_year % 10
            $stem_han       = $celestial[$stem_number]
            $stem_pinyin    = $pinyin[$stem_han]

            $element_number = [Math]::Floor($stem_number / 2)
            $element        = $elements[$element_number]

            $branch_number  = $cycle_year % 12
            $branch_han     = $terrestrial[$branch_number]
            $branch_pinyin  = $pinyin[$branch_han]
            $animal         = $animals[$branch_number]

            $aspect_number  = $cycle_year % 2
            $aspect         = $aspects[$aspect_number]

            $index          = $cycle_year % 60 + 1

            [PSCustomObject]@{
                Year        = $Year
                Element     = $element
                Animal      = $animal
                Aspect      = $aspect
                YearOfCycle = $index
                ASCII       = "$stem_pinyin-$branch_pinyin"
                Chinese     = "$stem_han$branch_han"
            }
        }
    }
}


:- initialization(main).

animals(['Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake', 'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig']).

elements(['Wood', 'Fire', 'Earth', 'Metal', 'Water']).

animal_chars(['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥']).

element_chars([['甲', '丙', '戊', '庚', '壬'], ['乙', '丁', '己', '辛', '癸']]).

years([1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017]).

year_animal(Year, Animal) :-
    I is ((Year - 4) mod 12) + 1,
    animals(Animals),
    nth(I, Animals, Animal).

year_element(Year, Element) :-
    I is ((Year - 4) mod 10) div 2 + 1,
    elements(Elements),
    nth(I, Elements, Element).

year_animal_char(Year, AnimalChar) :-
    I is (Year - 4) mod 12 + 1,
    animal_chars(AnimalChars),
    nth(I, AnimalChars, AnimalChar).

year_element_char(Year, ElementChar) :-
    I1 is Year mod 2 + 1,
    element_chars(ElementChars),
    nth(I1, ElementChars, ElementChars1),
    I2 is (Year - 4) mod 10 div 2 + 1,
    nth(I2, ElementChars1, ElementChar).

year_yin_yang(Year, YinYang) :-
    Year mod 2 =:= 0 -> YinYang = 'yang' ; YinYang = 'yin'.

main :-
    years(Years),
    forall(member(Year, Years), (
        write(Year),
        write(' is the year of the '),
        year_element(Year, Element),
        write(Element),
        write(' '),
        year_animal(Year, Animal),
        write(Animal),
        write(' '),
        year_yin_yang(Year, YinYang),
        write('('),
        write(YinYang),
        write('). '),
        year_element_char(Year, ElementChar),
        write(ElementChar),
        year_animal_char(Year, AnimalChar),
        write(AnimalChar),
        nl
    )).


EnableExplicit
#BASE=4
#SPC=Chr(32)

Procedure.s ChineseZodiac(n.i)
  Define cycle_year.i=n-#BASE,
         stem_number.i    = cycle_year%10+1,
         element_number.i = Round(stem_number/2,#PB_Round_Nearest),
         branch_number.i  = cycle_year%12+1,
         aspect_number.i  = cycle_year%2+1,
         index.i          = cycle_year%60+1,
         celestial$       = Chr(PeekU(?Celestial_stem+SizeOf(Character)*(stem_number-1))),
         c_pinyin$        = StringField(PeekS(?Stem),stem_number,"\"),
         element$         = StringField(PeekS(?Element),element_number,"\"),
         branch_han$      = Chr(PeekU(?Terrestrial_branch+SizeOf(Character)*(branch_number-1))),
         b_pinyin$        = StringField(PeekS(?Branch),branch_number,"\"),
         animal$          = StringField(PeekS(?Zodiac_animal),branch_number,"\"),
         aspect$          = StringField(PeekS(?Aspect),aspect_number,"\"),
         YearOfCycle$     = Str(index)
  ProcedureReturn Str(n)+#SPC+
                         LSet(element$,7,#SPC)+#SPC+
                         LSet(animal$,7,#SPC)+#SPC+
                         LSet(aspect$,6,#SPC)+#SPC+
                         RSet(YearOfCycle$,11)+#SPC+
                         LSet(c_pinyin$+"-"+b_pinyin$,9,#SPC)+#SPC+
                         celestial$+branch_han$
EndProcedure

LoadFont(0,"Consolas",12)
If OpenWindow(0,#PB_Ignore,#PB_Ignore,600,400,"Chinese Zodiac",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  EditorGadget(0, 8, 8, 600-16, 400-16) : SetGadgetFont(0,FontID(0))
  Define header$="Year Element Animal  Aspect YearOfCycle ASCII     Chinese"
  AddGadgetItem(0,-1,header$)
  AddGadgetItem(0,-1,ChineseZodiac(1935))
  AddGadgetItem(0,-1,ChineseZodiac(1938))
  AddGadgetItem(0,-1,ChineseZodiac(1968))
  AddGadgetItem(0,-1,ChineseZodiac(1972))
  AddGadgetItem(0,-1,ChineseZodiac(1976))
  AddGadgetItem(0,-1,ChineseZodiac(1984))
  AddGadgetItem(0,-1,ChineseZodiac(Year(Date())))
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

DataSection
  Celestial_stem: : Data.u $7532, $4E59, $4E19, $4E01, $620A, $5DF1, $5E9A, $8F9B, $58EC, $7678
  Terrestrial_branch: : Data.u $5B50, $4E11, $5BC5, $536F, $8FB0, $5DF3, $5348, $672A, $7533, $9149, $620C, $4EA5
  Zodiac_animal: : Data.s "Rat\Ox\Tiger\Rabbit\Dragon\Snake\Horse\Goat\Monkey\Rooster\Dog\Pig"
  Element: : Data.s "Wood\Fire\Earth\Metal\Water"
  Aspect: : Data.s "yang\yin"
  Stem: : Data.s "jiă\yĭ\bĭng\dīng\wù\jĭ\gēng\xīn\rén\gŭi"
  Branch: : Data.s "zĭ\chŏu\yín\măo\chén\sì\wŭ\wèi\shēn\yŏu\xū\hài"
EndDataSection


# coding: utf-8

from __future__ import print_function
from datetime import datetime

pinyin = {
  '甲': 'jiă',
  '乙': 'yĭ',
  '丙': 'bĭng',
  '丁': 'dīng',
  '戊': 'wù',
  '己': 'jĭ',
  '庚': 'gēng',
  '辛': 'xīn',
  '壬': 'rén',
  '癸': 'gŭi',

  '子': 'zĭ',
  '丑': 'chŏu',
  '寅': 'yín',
  '卯': 'măo',
  '辰': 'chén',
  '巳': 'sì',
  '午': 'wŭ',
  '未': 'wèi',
  '申': 'shēn',
  '酉': 'yŏu',
  '戌': 'xū',
  '亥': 'hài'
}

animals = ['Rat', 'Ox', 'Tiger', 'Rabbit', 'Dragon', 'Snake',
           'Horse', 'Goat', 'Monkey', 'Rooster', 'Dog', 'Pig']
elements = ['Wood', 'Fire', 'Earth', 'Metal', 'Water']

celestial = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']
terrestrial = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']
aspects = ['yang', 'yin']

def calculate(year):
    BASE = 4
    year = int(year)
    cycle_year = year - BASE
    stem_number = cycle_year % 10
    stem_han = celestial[stem_number]
    stem_pinyin = pinyin[stem_han]
    element_number = stem_number // 2
    element = elements[element_number]
    branch_number = cycle_year % 12
    branch_han = terrestrial[branch_number]
    branch_pinyin = pinyin[branch_han]
    animal = animals[branch_number]
    aspect_number = cycle_year % 2
    aspect = aspects[aspect_number]
    index = cycle_year % 60 + 1
    print("{}: {}{} ({}-{}, {} {}; {} - year {} of the cycle)"
          .format(year, stem_han, branch_han,
                  stem_pinyin, branch_pinyin, element, animal, aspect, index))

current_year = datetime.now().year
years = [1935, 1938, 1968, 1972, 1976, current_year]
for year in years:
    calculate(year)


#lang racket

(require racket/date)

; Any CE Year that was the first of a 60-year cycle
(define base-year 1984)

(define celestial-stems '("甲" "乙" "丙" "丁" "戊" "己" "庚" "辛" "壬" "癸"))

(define terrestrial-branches '("子" "丑" "寅" "卯" "辰" "巳" "午" "未" "申" "酉" "戌" "亥"))

(define zodiac-animals
  '("Rat" "Ox" "Tiger" "Rabbit" "Dragon" "Snake" "Horse" "Goat" "Monkey" "Rooster" "Dog" "Pig"))

(define elements '("Wood" "Fire" "Earth" "Metal" "Water"))

(define aspects '("yang" "yin"))

(define pinyin
  (map cons
       (append celestial-stems terrestrial-branches)
       (list "jiă" "yĭ" "bĭng" "dīng" "wù" "jĭ" "gēng" "xīn" "rén" "gŭi"
             "zĭ" "chŏu" "yín" "măo" "chén" "sì" "wŭ" "wèi" "shēn" "yŏu" "xū" "hài")))

(define (this-year) (date-year (current-date)))

(define (pinyin-for han) (cdr (assoc han pinyin)))

(define (han/pinyin-nth n hans) (let ((han (list-ref hans n))) (values han (pinyin-for han))))

(define (chinese-zodiac ce-year)
  (let* ((cycle-year (- ce-year base-year))
         (stem-number    (modulo cycle-year (length celestial-stems)))
         (element-number (quotient stem-number 2))
         (aspect-number  (modulo cycle-year (length aspects)))
         (branch-number  (modulo cycle-year (length terrestrial-branches)))
         (element        (list-ref elements element-number))
         (zodiac-animal  (list-ref zodiac-animals branch-number))
         (aspect         (list-ref aspects aspect-number)))
    (let-values (([stem-han stem-pinyin]     (han/pinyin-nth stem-number celestial-stems))
                 ([branch-han branch-pinyin] (han/pinyin-nth branch-number terrestrial-branches)))
      (list ce-year stem-han branch-han stem-pinyin branch-pinyin element zodiac-animal aspect))))

(module+ test
  (for ((ce-year (in-list '(1935 1938 1941 1947 1968 1972 1976))))
  (apply printf "~a: ~a~a (~a-~a, ~a ~a; ~a)~%" (chinese-zodiac ce-year))))


sub Chinese-zodiac ( Int $year ) {
    my @heaven  = <甲 jiă 乙 yĭ 丙 bĭng 丁 dīng 戊 wù 己 jĭ 庚 gēng 辛 xīn 壬 rén 癸 gŭi>.pairup;
    my @earth   = <子 zĭ 丑 chŏu 寅 yín 卯 măo 辰 chén 巳 sì 午 wŭ 未 wèi 申 shēn 酉 yŏu 戌 xū 亥 hài>.pairup;
    my @animal  = <Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig>;
    my @element = <Wood Fire Earth Metal Water>;
    my @aspect  = <yang yin>;

    my $cycle_year = ($year - 4) % 60;
    my $i2         = $cycle_year % 2;
    my $i10        = $cycle_year % 10;
    my $i12        = $cycle_year % 12;

    %(
        'Han'     => @heaven[$i10].key ~ @earth[$i12].key,
        'pinyin'  => @heaven[$i10].value ~ @earth[$i12].value,
        'heaven'  => @heaven[$i10],
        'earth'   => @earth[$i12],
        'element' => @element[$i10 div 2],
        'animal'  => @animal[$i12],
        'aspect'  => @aspect[$i2],
        'cycle'   => $cycle_year + 1
    )
}

# TESTING
printf "%d: %s (%s, %s %s; %s - year %d in the cycle)\n",
    $_, .&Chinese-zodiac<Han pinyin element animal aspect cycle>
    for 1935, 1938, 1968, 1972, 1976, 1984, Date.today.year;


yinyang  = ["yang", "yin"]
elements = ["Wood", "Fire", "Earth", "Metal", "Water"]
animals  = ["Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
            "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig"]
years    = [1801, 1861, 1984, 2020, 2186, 76543]
output   = ""

for year in years
    yy      = year % 2 + 1
    element = (year - 4) % 5 + 1
    animal  = (year - 4) % 12 + 1
    output  = string(year) + " is the year of the "
    output += elements[element] + " " + animals[animal] + " (" + yinyang[yy] + ")."
    ? output
next


# encoding: utf-8
pinyin = {
  '甲' => 'jiă',
  '乙' => 'yĭ',
  '丙' => 'bĭng',
  '丁' => 'dīng',
  '戊' => 'wù',
  '己' => 'jĭ',
  '庚' => 'gēng',
  '辛' => 'xīn',
  '壬' => 'rén',
  '癸' => 'gŭi',

  '子' => 'zĭ',
  '丑' => 'chŏu',
  '寅' => 'yín',
  '卯' => 'măo',
  '辰' => 'chén',
  '巳' => 'sì',
  '午' => 'wŭ',
  '未' => 'wèi',
  '申' => 'shēn',
  '酉' => 'yŏu',
  '戌' => 'xū',
  '亥' => 'hài'
}
celestial     = %w(甲 乙 丙 丁 戊 己 庚 辛 壬 癸)
terrestrial   = %w(子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥)
animals       = %w(Rat   Ox   Tiger  Rabbit  Dragon Snake
                   Horse Goat Monkey Rooster Dog    Pig)
elements      = %w(Wood Fire Earth Metal Water)
aspects       = %w(yang yin)

BASE = 4

args = if !ARGV.empty?
         ARGV
       else
         [Time.new.year]
       end

args.each do |arg|
  ce_year = Integer(arg)
  print "#{ce_year}: " if ARGV.length > 1
  cycle_year     = ce_year - BASE

  stem_number    = cycle_year % 10
  stem_han       = celestial[stem_number]
  stem_pinyin    = pinyin[stem_han]

  element_number = stem_number / 2
  element        = elements[element_number]

  branch_number  = cycle_year % 12
  branch_han     = terrestrial[branch_number]
  branch_pinyin  = pinyin[branch_han]
  animal         = animals[branch_number]

  aspect_number = cycle_year % 2
  aspect        = aspects[aspect_number]

  index         = cycle_year % 60 + 1

  print stem_han, branch_han
  puts " (#{stem_pinyin}-#{branch_pinyin}, #{element} #{animal}; #{aspect} - year #{index} of the cycle)"
end


fn chinese_zodiac(year: usize) -> String {
    static ANIMALS: [&str; 12] = [
        "Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake",
        "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig",
    ];
    static ASPECTS: [&str; 2] = ["Yang", "Yin"];
    static ELEMENTS: [&str; 5] = ["Wood", "Fire", "Earth", "Metal", "Water"];
    static STEMS: [char; 10] = [
        '甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸',
    ];
    static BRANCHES: [char; 12] = [
        '子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥',
    ];
    static S_NAMES: [&str; 10] = [
        "jiă", "yĭ", "bĭng", "dīng", "wù", "jĭ", "gēng", "xīn", "rén", "gŭi",
    ];
    static B_NAMES: [&str; 12] = [
        "zĭ", "chŏu", "yín", "măo", "chén", "sì",
        "wŭ", "wèi", "shēn", "yŏu", "xū", "hài",
    ];

    let y = year - 4;
    let s = y % 10;
    let b = y % 12;

    let stem = STEMS[s];
    let branch = BRANCHES[b];
    let s_name = S_NAMES[s];
    let b_name = B_NAMES[b];
    let element = ELEMENTS[s / 2];
    let animal = ANIMALS[b];
    let aspect = ASPECTS[s % 2];
    let cycle = y % 60 + 1;

    format!(
        "{}    {}{}    {:9}  {:7}  {:7}  {:6}  {:02}/60",
        year,
        stem,
        branch,
        format!("{}-{}", s_name, b_name),
        element,
        animal,
        aspect,
        cycle
    )
}

fn main() {
    let years = [1935, 1938, 1968, 1972, 1976, 1984, 2017];
    println!("Year  Chinese  Pinyin     Element  Animal   Aspect  Cycle");
    println!("----  -------  ---------  -------  -------  ------  -----");
    for &year in &years {
        println!("{}", chinese_zodiac(year));
    }
}


object Zodiac extends App {
  val years = Seq(1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017, 2018)

  private def animals =
    Seq("Rat",
      "Ox",
      "Tiger",
      "Rabbit",
      "Dragon",
      "Snake",
      "Horse",
      "Goat",
      "Monkey",
      "Rooster",
      "Dog",
      "Pig")

  private def animalChars =
    Seq("子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥")

  private def elements = Seq("Wood", "Fire", "Earth", "Metal", "Water")

  private def elementChars =
    Seq(Array("甲", "丙", "戊", "庚", "壬"), Array("乙", "丁", "己", "辛", "癸"))

  private def getYY(year: Int) = if (year % 2 == 0) "yang" else "yin"

  for (year <- years) {
    println(year
      + " is the year of the " + elements(math.floor((year - 4) % 10 / 2).toInt) + " "
      + animals((year - 4) % 12)
      + " (" + getYY(year) + "). "
      + elementChars(year % 2)(math.floor((year - 4) % 10 / 2).toInt)
      + animalChars((year - 4) % 12))
  }
}


$ include "seed7_05.s7i";
  include "console.s7i";

const array string: animals is [0] ("Rat", "Ox", "Tiger", "Rabbit", "Dragon", "Snake", "Horse", "Goat", "Monkey", "Rooster", "Dog", "Pig");
const array string: elements is [0] ("Wood", "Fire", "Earth", "Metal", "Water");
const array string: animalChars is [0] ("子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥");
const array array string: elementChars is [0] ([0] ("甲", "丙", "戊", "庚", "壬"), [0] ("乙", "丁", "己", "辛", "癸"));

const proc: main is func
  local
    var integer: year is 0;
    var integer: eIdx is 0;
    var integer: aIdx is 0;
  begin
    OUT := STD_CONSOLE;
    for year range {1935, 1938, 1968, 1972, 1976, 1984, 1985, 2017} do
      eIdx := (year - 4) rem 10 div 2;
      aIdx := (year - 4) rem 12;
      writeln(year <& " is the year of the " <& elements[eIdx] <& " " <& animals[aIdx] <& " (" <&
              ([0] ("yang", "yin"))[year rem 2] <& "). " <& elementChars[year rem 2][eIdx] <& animalChars[aIdx]);
    end for;
  end func;


func zodiac(year) {
  var animals = %w(Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig)
  var elements = %w(Wood Fire Earth Metal Water)
  var terrestrial_han = %w(子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥)
  var terrestrial_pinyin = %w(zĭ chŏu yín măo chén sì wŭ wèi shēn yŏu xū hài)
  var celestial_han = %w(甲 乙 丙 丁 戊 己 庚 辛 壬 癸)
  var celestial_pinyin = %w(jiă yĭ bĭng dīng wù jĭ gēng xīn rén gŭi)
  var aspect = %w(yang yin)

  var cycle_year = ((year-4) % 60)
  var (i2, i10, i12) = (cycle_year%2, cycle_year%10, cycle_year%12)

  (year,
   celestial_han[i10],    terrestrial_han[i12],
   celestial_pinyin[i10], terrestrial_pinyin[i12],
   elements[i10 >> 1], animals[i12], aspect[i2], cycle_year+1)
}

[1935, 1938, 1968, 1972, 1976, 2017].each { |year|
    printf("%4d: %s%s (%s-%s) %s %s; %s - year %d of the cycle\n", zodiac(year))
}


	DATA "甲","乙","丙","丁","戊","己","庚","辛","壬","癸"
	DECLARE celestial$(10)
	MAT READ celestial$

	DATA "子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"
	DECLARE terrestrial$(12)
	MAT READ terrestrial$

	DATA "Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"
	DECLARE animals$(12)
	MAT READ animals$

        DATA "Wood","Fire","Earth","Metal","Water"
	DECLARE elements$(5)
	MAT READ elements$

	DATA "yang","yin"
	DECLARE aspects$(2)
	MAT READ aspects$

	DATA "jiă","yĭ","bĭng","dīng","wù","jĭ","gēng","xīn","rén","gŭi"
	DATA "zĭ","chŏu","yín","măo","chén","sì","wŭ","wèi","shēn","yŏu","xū","hài"
	DECLARE celestialpinyin$(UBOUND(celestial$(),1))
	DECLARE terrestrialpinyin$(UBOUND(terrestrial$(),1))
	MAT READ celestialpinyin$
	MAT READ terrestrialpinyin$

	DATA 1935,1938,1931,1961,1963,1991,1993,1996,2001
	DECLARE years(9)
	MAT READ years

	DECLARE _base = 4
	DECLARE _year
	DECLARE cycleyear
	DECLARE stemnumber
	DECLARE stemhan$
	DECLARE stempinyin$
	DECLARE elementnumber
	DECLARE element$
	DECLARE branchnumber
	DECLARE branchhan$
	DECLARE branchpinyin$
	DECLARE animal$
	DECLARE aspectnumber
	DECLARE aspect$
	DECLARE index

	DECLARE i
	DECLARE top = UBOUND(years(),1)
	FOR i = 1 TO top
		_year = years(i)
		cycleyear = _year - _base
		stemnumber = MOD(cycleyear, 10)
		stemhan$    = celestial$(stemnumber + 1)
		stempinyin$ = celestialpinyin$(stemnumber + 1)
		elementnumber = div(stemnumber, 2) + 1
		element$       = elements$(elementnumber)
		branchnumber = MOD(cycleyear, 12)
		branchhan$    = terrestrial$(branchnumber + 1)
		branchpinyin$ = terrestrialpinyin$(branchnumber + 1)
		animal$       = animals$(branchnumber + 1)
		aspectnumber = MOD(cycleyear, 2)
		aspect$       = aspects$(aspectnumber + 1)
		index = MOD(cycleyear, 60) + 1
		PRINT _year;
		PRINT TAB(5);stemhan$+branchhan$;
		PRINT TAB(12);stempinyin$;"-";branchpinyin$;
		PRINT TAB(25);element$;" ";animal$;" ("+aspect$+")";
		PRINT TAB(50);"year";index;"of the cycle"
	NEXT


proc cn_zodiac year {
   set year0 [expr $year-4]
   set animals {Rat Ox Tiger Rabbit Dragon Snake Horse Goat Monkey Rooster Dog Pig}
   set elements {Wood Fire Earth Metal Water}
   set stems {jia3 yi3 bing3 ding1 wu4 ji3 geng1 xin1 ren2 gui3}
   set gan {\u7532 \u4E59 \u4E19 \u4E01 \u620A \u5DF1 \u5E9A \u8F9B \u58EC \u7678}
   set branches {zi3 chou3 yin2 mao3 chen2 si4 wu3 wei4 shen1 you3 xu1 hai4}
   set zhi {\u5B50 \u4E11 \u5BC5 \u536F \u8FB0 \u5DF3 \u5348 \u672A \u7533 \u9149 \u620C \u4EA5}
   set m10 [expr $year0%10]
   set m12 [expr $year0%12]
   set res [lindex $gan $m10][lindex $zhi $m12]
   lappend res [lindex $stems $m10]-[lindex $branches $m12]
   lappend res [lindex $elements [expr $m10/2]]
   lappend res [lindex $animals $m12] ([expr {$year0%2 ? "yin" : "yang"}])
   lappend res year [expr $year0%60+1]
   return $res
}


dim @y(2)                              ' yin or yang
dim @e(5)                              ' the elements
dim @a(12)                             ' the animals

Push Dup("yang"), Dup("yin")           ' fill Ying/Yang table
For i = 1 to 0 step -1 : @y(i) = Pop() : Next i
                                       ' fill Elements table
Push Dup("Wood"), Dup("Fire"), Dup("Earth"), Dup("Metal"), Dup("Water")
For i = 4 to 0 step -1 : @e(i) = Pop() : Next i
                                       ' fill Animals table
Push Dup("Rat"),   Dup("Ox"),    Dup("Tiger"), Dup("Rabbit"), Dup("Dragon")
Push Dup("Snake"), Dup("Horse"), Dup("Goat"),  Dup("Monkey"), Dup("Rooster")
Push Dup("Dog"),   Dup("Pig")

For i = 11 to 0 step -1 : @a(i) = Pop() : Next i
                                       ' now push all the test years
Push 76543, 2186, 2020, 1984, 1861, 1801
                                       ' and process them all
Do While Used()                        ' until the stack is empty
  Print Show(FUNC(_Chinese(Pop())))    ' call function
Loop

End

_Chinese                               ' compose string
  Param (1)
  Local (3)

  [email protected] = [email protected] % 2
  [email protected] = ([email protected] - 4) % 5
  [email protected] = ([email protected] - 4) % 12
Return (Join(Str ([email protected]), " is the year of the ", @e([email protected]), " ", @a([email protected]), " (", @y([email protected]), ")."))