Yin and yang

From Rosetta Code
Revision as of 23:10, 18 April 2011 by rosettacode>Dkf (→‎{{header|Tcl}}: Add link to file (which is about to be created))
Yin and yang is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Create a function that given a variable representing size, generates a Yin and yang also known as a Taijitu symbol scaled to that size.

Generate and display the symbol generated for two different (small) sizes.

D

This example is incorrect. Please fix the code and remove this message.

Details: The output does not sufficiently resemble a Yin-yang symbol.

<lang d>import std.stdio, std.string, std.algorithm ;

enum { Void = 0, Yan = 1, Yin = 2, I = 3} ; enum Tiles = [" ","·","#","?"] ;

alias int delegate(int) Draw ;

struct Board { // a square board

   immutable int scale ;
   immutable int size ;
   int[][] pix ;
   this(int s) {
       scale = s ;
       size = s*12 ;
       pix = new int[][](size + 1,size + 1) ;
   }
   alias pix this ;

   static string str(int v) { return Tiles[(v % 4)] ; }

   string toString() {
       string[] s ;
       foreach( r ; pix)
           s ~= reduce!"a~b"(map!str(r)) ;
       return s.join("\n") ;
   }

   void drawCircle(int cx, int cy, int cr, Draw action) {
       auto rr = (cr*scale)^^2 ;
       foreach(y, ref r ; pix)
           foreach( x , ref v ; r) {
               auto dx = x - cx*scale ;
               auto dy = y - cy*scale ;
               if(dx^^2 + dy^^2 <= rr)
                   v = action(x) ;
           }
   }

   Board yanYin() {
       foreach(r ; pix) // clear
           r[] = 0 ;
       drawCircle(6,6,6, (int x) { return (x < 6*scale) ? Yan : Yin ; }) ;
       drawCircle(6,3,3, (int x) { return Yan ; } ) ;
       drawCircle(6,9,3, (int x) { return Yin ; } ) ;
       drawCircle(6,9,1, (int x) { return Yan ; } ) ;
       drawCircle(6,3,1, (int x) { return Yin ; } ) ;
       return this ;
   }

}

void main(string[] args) {

   writeln(Board(2).yanYin) ;
   writeln(Board(1).yanYin) ;

}</lang> Output:

            ·            
        ········#        
      ···········##      
     ·············##     
    ········#·····###    
   ········###····####   
  ········#####····####  
  ·········###····#####  
 ···········#·····###### 
 ·················###### 
 ················####### 
 ···············######## 
············#############
 ········############### 
 ·······################ 
 ······################# 
 ······#####·########### 
  ·····####···#########  
  ····####·····########  
   ····####···########   
    ···#####·########    
     ··#############     
      ··###########      
        ·########        
            #            
      ·      
   ······#   
  ····#··##  
 ····###··## 
 ·····#··### 
 ········### 
······#######
 ···######## 
 ···##·##### 
 ··##···#### 
  ··##·####  
   ·######   
      #      

J

Based on the Python implementation:

<lang j>yinyang=:3 :0

 radii=. y*1 3 6
 ranges=. i:each radii
 squares=. ,"0/~each ranges
 circles=. radii ([ >: +/"1&.:*:@])each squares
 cInds=. ({:radii) +each circles #&(,/)each squares
 M=. ' *.' {~  circles (*  1 + 0 >: {:"1)&(_1&{::) squares
 offset=. 3*y,0
 M=. '*' ((_2 {:: cInds) <@:+"1 offset)} M
 M=. '.' ((_2 {:: cInds) <@:-"1 offset)} M
 M=. '.' ((_3 {:: cInds) <@:+"1 offset)} M
 M=. '*' ((_3 {:: cInds) <@:-"1 offset)} M

)</lang>

Note: although the structure of this program is based on the python implementation, some details are different. In particular, in the python implementation, the elements of squares and circles have no x,y structure -- they are flat list of coordinates.

Here, the three squares are each 3 dimensional arrays. The first two dimensions correspond to the x and y values and the last dimension is 2 (the first value being the y coordinate and the second being the x coordinate -- having the dimensions as y,x pairs like this works because in J the first dimension of a matrix is the number of rows and the second dimension is the number of columns).

Also, the three elements in the variable circles are represented by 2 dimensional arrays. The dimensions correspond to x and y values and the values are bits -- 1 if the corresponding coordinate pair in squares is a member of the circle and 0 if not.

Finally, the variable cInds corresponds very closely to the variable circles in the python code. Except, instead of having y and x values, cInds has indices into M. In other words, I added the last value from radii to the y and x values. In other words, instead of having values in the range -18..18, I would have values in the range 0..36 (but replace 18 and 36 with whatever values are appropriate).

Example use:

<lang> yinyang 1

     .      
  ......*   
 ....*..**  
....***..** 
.....*..*** 
........*** 

.......******

...******** 
...**.***** 
..**...**** 
 ..**.****  
  .******   
     *      
  yinyang 2
           .            
       ........*        
     ...........**      
    .............**     
   ........*.....***    
  ........***....****   
 ........*****....****  
 .........***....*****  
...........*.....****** 
.................****** 
................******* 
...............******** 

.............************

........*************** 
.......**************** 
......***************** 
......*****.*********** 
 .....****...*********  
 ....****.....********  
  ....****...********   
   ...*****.********    
    ..*************     
     ..***********      
       .********        
           *            </lang>

Python

For positive integer n > 0, the following generates an ASCII representation of the Yin yang symbol.

Works with: Python version 3.x

<lang python>import math def yinyang(n=3): radii = [i * n for i in (1, 3, 6)] ranges = [list(range(-r, r+1)) for r in radii] squares = [[ (x,y) for x in rnge for y in rnge] for rnge in ranges] circles = [[ (x,y) for x,y in sqrpoints if math.hypot(x,y) <= radius ] for sqrpoints, radius in zip(squares, radii)] m = {(x,y):' ' for x,y in squares[-1]} for x,y in circles[-1]: m[x,y] = '*' for x,y in circles[-1]: if x>0: m[(x,y)] = '·' for x,y in circles[-2]: m[(x,y+3*n)] = '*' m[(x,y-3*n)] = '·' for x,y in circles[-3]: m[(x,y+3*n)] = '·' m[(x,y-3*n)] = '*' return '\n'.join(.join(m[(x,y)] for x in reversed(ranges[-1])) for y in ranges[-1])</lang>

Sample generated symbols for n = 2 and n = 3
>>> print(yinyang(2))
            ·            
        ········*        
      ···········**      
     ·············**     
    ········*·····***    
   ········***····****   
  ········*****····****  
  ·········***····*****  
 ···········*·····****** 
 ·················****** 
 ················******* 
 ···············******** 
·············************
 ········*************** 
 ·······**************** 
 ······***************** 
 ······*****·*********** 
  ·····****···*********  
  ····****·····********  
   ····****···********   
    ···*****·********    
     ··*************     
      ··***********      
        ·********        
            *            
>>> print(yinyang(1))
      ·      
   ······*   
  ····*··**  
 ····***··** 
 ·····*··*** 
 ········*** 
·······******
 ···******** 
 ···**·***** 
 ··**···**** 
  ··**·****  
   ·******   
      *      
>>> 

Tcl

Output of this Tcl program
Library: Tk

<lang tcl>package require Tcl 8.5 package require Tk

namespace import tcl::mathop::\[-+\]  ;# Shorter coordinate math proc yinyang {c x y r {colors {white black}}} {

   lassign $colors a b
   set tt [expr {$r * 2 / 3.0}]
   set h [expr {$r / 2.0}]
   set t [expr {$r / 3.0}]
   set s [expr {$r / 6.0}]
   $c create arc [- $x $r] [- $y $r] [+ $x $r] [+ $y $r] \

-fill $a -outline {} -extent 180 -start 90

   $c create arc [- $x $r] [- $y $r] [+ $x $r] [+ $y $r] \

-fill $b -outline {} -extent 180 -start 270

   $c create oval [- $x $h] [- $y $r] [+ $x $h] $y \

-fill $a -outline {}

   $c create oval [- $x $h] [+ $y $r] [+ $x $h] $y \

-fill $b -outline {}

   $c create oval [- $x $s] [- $y $tt] [+ $x $s] [- $y $t] \

-fill $b -outline {}

   $c create oval [- $x $s] [+ $y $tt] [+ $x $s] [+ $y $t] \

-fill $a -outline {} }

pack [canvas .c -width 300 -height 300 -background gray50] yinyang .c 110 110 90 yinyang .c 240 240 40</lang>