Yin and yang
You are encouraged to solve this task according to the task description, using any language you may know.
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.
Asymptote
<lang asymptote>unitsize(1 inch);
fill(scale(6)*unitsquare, invisible);
picture yinyang(pair center, real radius) {
picture p; fill(p, unitcircle, white); fill(p, arc(0, S, N) -- cycle, black); fill(p, circle(N/2, 1/2), white); fill(p, circle(S/2, 1/2), black); fill(p, circle(N/2, 1/5), black); fill(p, circle(S/2, 1/5), white); draw(p, unitcircle, linewidth((1/32) * inch) + gray(0.5)); return shift(center) * scale(radius) * p;
}
add(yinyang((1 + 1/4, 4 + 3/4), 1)); add(yinyang((3 + 3/4, 2 + 1/4), 2));</lang>
D
<lang d>import std.stdio, std.string, std.algorithm, std.array;
struct SquareBoard {
enum W : char { Void=' ', Yan='.', Yin='#', I='?' };
immutable int scale; W[][] pix;
this(int s) { scale = s; pix = new W[][](s * 12 + 1, s * 12 + 1); }
string toString() { auto rows = map!q{ (cast(char[])a).idup }(pix); return join(array(rows), "\n"); }
void drawCircle(Draw)(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); } }
SquareBoard yanYin() { foreach (r; pix) // clear r[] = W.Void; drawCircle(6, 6, 6, (int x){ return (x < 6*scale) ? W.Yan : W.Yin; }); drawCircle(6, 3, 3, (int x){ return W.Yan; }); drawCircle(6, 9, 3, (int x){ return W.Yin; }); drawCircle(6, 9, 1, (int x){ return W.Yan; }); drawCircle(6, 3, 1, (int x){ return W.Yin; }); return this; }
}
void main() {
writeln(SquareBoard(2).yanYin()); writeln(SquareBoard(1).yanYin());
}</lang> Output:
· ········# ···········## ·············## ········#·····### ········###····#### ········#####····#### ·········###····##### ···········#·····###### ·················###### ················####### ···············######## ············############# ········############### ·······################ ······################# ······#####·########### ·····####···######### ····####·····######## ····####···######## ···#####·######## ··############# ··########### ·######## # · ······# ····#··## ····###··## ·····#··### ········### ······####### ···######## ···##·##### ··##···#### ··##·#### ·###### #
Delphi
<lang delphi>procedure TForm1.ButtonCreateClick(Sender: TObject);
begin
DrawYinAndYang(StrToInt(EditSize.Text), Canvas, GetClientRect);
end;
procedure DrawYinandYang(size: Word; DrawArea: TCanvas; R: TRect); begin
DrawArea.Brush.Color := clGray; DrawArea.FillRect(R); DrawArea.Brush.Color := clwhite; DrawArea.Pen.Color := clwhite; DrawArea.Pie(10, 10, 10 + size, 10 + size, 10 + (size div 2), 10, 10 + (size div 2), 10 + size); DrawArea.Brush.Color := clblack; DrawArea.Pen.Color := clblack; DrawArea.Pie(10, 10, 10 + size, 10 + size, 10 + (size div 2), 10 + size, 10 + (size div 2), 10); DrawArea.Brush.Color := clwhite; DrawArea.Pen.Color := clwhite; DrawArea.Ellipse(10 + (size div 4), 10, 10 + 3 * (size div 4),10 + (size div 2)); DrawArea.Brush.Color := clblack; DrawArea.Pen.Color := clblack; DrawArea.Ellipse(10 + (size div 4), 10 + (size div 2), 10 + 3 * (size div 4), 10 + size); DrawArea.Brush.Color := clwhite; DrawArea.Pen.Color := clwhite; DrawArea.Ellipse(10 + 7 * (size div 16), 10 + 11 * (size div 16), 10 + 9 * (size div 16),10 + 13 * (size div 16)); DrawArea.Brush.Color := clblack; DrawArea.Pen.Color := clblack; DrawArea.Ellipse(10 + 7 * (size div 16), 10 + 3 * (size div 16), 10 + 9 * (size div 16),10 + 5 * (size div 16));
end;</lang>
Icon and Unicon
<lang Icon>link graphics
procedure main() YinYang(100) YinYang(40,"blue","yellow","white") WDone() # quit on Q/q end
procedure YinYang(R,lhs,rhs,bg) # draw YinYang with radius of R pixels and ... /lhs := "white" # left hand side /rhs := "black" # right hand side /bg := "grey" # background
wsize := 2*(C := R + (margin := R/5))
W := WOpen("size="||wsize||","||wsize,"bg="||bg) | stop("Unable to open Window") WAttrib(W,"fg="||lhs) & FillCircle(W,C,C,R,+dtor(90),dtor(180)) # main halves WAttrib(W,"fg="||rhs) & FillCircle(W,C,C,R,-dtor(90),dtor(180)) WAttrib(W,"fg="||lhs) & FillCircle(W,C,C+R/2,R/2,-dtor(90),dtor(180)) # sub halves WAttrib(W,"fg="||rhs) & FillCircle(W,C,C-R/2,R/2,dtor(90),dtor(180)) WAttrib(W,"fg="||lhs) & FillCircle(W,C,C-R/2,R/8) # dots WAttrib(W,"fg="||rhs) & FillCircle(W,C,C+R/2,R/8) end </lang>
graphics.icn provides graphical procedures
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>
Liberty BASIC
<lang lb> txt$ = "Hello World! "
WindowWidth =410 WindowHeight =440
open "Yin & Yang" for graphics_nf_nsb as #w
#w "trapclose [quit]"
call YinYang 200, 200, 200 call YinYang 120, 50, 50
wait
sub YinYang x, y, size
#w "up ; goto "; x; " "; y #w "backcolor black ; color black" #w "down ; circlefilled "; size /2
#w "color 255 255 255 ; backcolor 255 255 255" #w "up ; goto "; x -size /2; " "; y -size /2 #w "down ; boxfilled "; x; " "; y +size /2
#w "up ; goto "; x; " "; y -size /4 #w "down ; backcolor black ; color black ; circlefilled "; size /4 #w "up ; goto "; x; " "; y -size /4 #w "down ; backcolor white ; color white ; circlefilled "; size /12
#w "up ; goto "; x; " "; y +size /4 #w "down ; backcolor white ; color white ; circlefilled "; size /4 #w "up ; goto "; x; " "; y +size /4 #w "down ; backcolor black ; color black ; circlefilled "; size /12
#w "up ; goto "; x; " "; y #w "down ; color black ; circle "; size /2
#w "flush"
end sub
scan
wait
[quit] close #w end
</lang>
UCB Logo
<lang logo> to taijitu :r
; Draw a classic Taoist taijitu of the given radius centered on the current ; turtle position. The "eyes" are placed along the turtle's heading, the ; filled one in front, the open one behind.
; don't bother doing anything if the pen is not down if not pendown? [stop]
; useful derivative values localmake "r2 r/2 localmake "r4 r/4 localmake "r8 r/8
; remember where we started localmake "start pos
; draw outer circle pendown arc 360 :r
; draw upper half of S penup forward r2 pendown arc 180 r2 ; and filled inner eye arc 360 r8 fill
; draw lower half of S penup back r pendown arc -180 r2
; other inner eye arc 360 r8
; fill this half of the symbol penup forward r4 pendown fill
; put the turtle back where it started penup setpos start pendown
end
- demo code to produce image at right
clearscreen pendown hideturtle taijitu 100 penup forward 150 left 90 forward 150 pendown taijitu 75
</lang>
Mathematica
Mathematica's ability to symbolically build up graphics is often underrated. The following function will create a yin-yang symbol with the parameter size indicating the diameter in multiples of 40 pixels.
<lang Mathematica>
YinYang[size_] :=
Graphics[{{Circle[{0, 0}, 2]}, {Disk[{0, 0}, 2, {90 Degree, -90 Degree}]}, {White, Disk[{0, 1}, 1]}, {Black, Disk[{0, -1}, 1]}, {Black, Disk[{0, 1}, 1/4]}, {White, Disk[{0, -1}, 1/4]}}, ImageSize -> 40 size]
</lang>
Prolog
Works with SWI-Prolog and XPCE.
<lang Prolog>ying_yang(N) :- R is N * 100, sformat(Title, 'Yin Yang ~w', [N]), new(W, window(Title)), new(Wh, colour(@default, 255*255, 255*255, 255*255)), new(Bl, colour(@default, 0, 0, 0)), CX is R + 50, CY is R + 50, R1 is R / 2, R2 is R / 8, CY1 is R1 + 50, CY2 is 3 * R1 + 50,
new(E, semi_disk(point(CX, CY), R, w, Bl)), new(F, semi_disk(point(CX, CY), R, e, Wh)), new(D1, disk(point(CX, CY1), R, Bl)), new(D2, disk(point(CX, CY2), R, Wh)), new(D3, disk(point(CX, CY1), R2, Wh)), new(D4, disk(point(CX, CY2), R2, Bl)),
send_list(W, display, [E, F, D1, D2, D3, D4]),
WD is 2 * R + 100, send(W, size, size(WD, WD )), send(W, open).
- - pce_begin_class(semi_disk, path, "Semi disk with color ").
initialise(P, C, R, O, Col) :->
send(P, send_super, initialise),
get(C, x, CX), get(C, y, CY), choose(O, Deb, End), forall(between(Deb, End, I), ( X is R * cos(I * pi/180) + CX, Y is R * sin(I * pi/180) + CY, send(P, append, point(X,Y)))), send(P, closed, @on), send(P, fill_pattern, Col).
- - pce_end_class.
choose(s, 0, 180). choose(n, 180, 360). choose(w, 90, 270). choose(e, -90, 90).
- - pce_begin_class(disk, ellipse, "disk with color ").
initialise(P, C, R, Col) :->
send(P, send_super, initialise, R, R),
send(P, center, C), send(P, pen, 0), send(P, fill_pattern, Col).
- - pce_end_class.
</lang> Example of output :
?- ying_yang(1). true. ?- ying_yang(2). true.
Python
For positive integer n > 0, the following generates an ASCII representation of the Yin yang symbol.
<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
andn = 3
>>> print(yinyang(2)) · ········* ···········** ·············** ········*·····*** ········***····**** ········*****····**** ·········***····***** ···········*·····****** ·················****** ················******* ···············******** ·············************ ········*************** ·······**************** ······***************** ······*****·*********** ·····****···********* ····****·····******** ····****···******** ···*****·******** ··************* ··*********** ·******** * >>> print(yinyang(1)) · ······* ····*··** ····***··** ·····*··*** ········*** ·······****** ···******** ···**·***** ··**···**** ··**·**** ·****** * >>>
SVG
SVG has no proper functions or variables, but we can translate and rescale a shape after defining it.
<lang xml><?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink" width="600" height="600">
<symbol id="yinyang">
<g transform="translate(-0.5, -0.5)"> <circle cx="0.5" cy="0.5" r="0.5" fill="white"/> <path d="M 0.5,0 A 0.5,0.5 0 0,1 0.5,1 z" fill="black"/> <circle cx="0.5" cy="0.25" r="0.25" fill="white"/> <circle cx="0.5" cy="0.75" r="0.25" fill="black"/> <circle cx="0.5" cy="0.25" r="0.1" fill="black"/> <circle cx="0.5" cy="0.75" r="0.1" fill="white"/> <circle cx="0.5" cy="0.5" r="0.5" fill="none" stroke="gray" stroke-width=".01"/> </g>
</symbol>
<use xlink:href="#yinyang"
transform="translate(125, 125) scale(200, 200)"/>
<use xlink:href="#yinyang"
transform="translate(375, 375) scale(400, 400)"/>
</svg></lang>
Tcl
<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>
Visual Basic .NET
This version is based behind a Windows Form Application project in Visual Studio, single form with base values. <lang vbnet> Public Class Form1
Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint Dim g As Graphics = e.Graphics g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
DrawTaijitu(g, New Point(50, 50), 200, True) DrawTaijitu(g, New Point(10, 10), 60, True) End Sub
Private Sub DrawTaijitu(ByVal g As Graphics, ByVal pt As Point, ByVal width As Integer, ByVal hasOutline As Boolean) g.FillPie(Brushes.Black, pt.X, pt.Y, width, width, 90, 180) g.FillPie(Brushes.White, pt.X, pt.Y, width, width, 270, 180) g.FillEllipse(Brushes.Black, CSng(pt.X + (width * 0.25)), CSng(pt.Y), CSng(width * 0.5), CSng(width * 0.5)) g.FillEllipse(Brushes.White, CSng(pt.X + (width * 0.25)), CSng(pt.Y + (width * 0.5)), CSng(width * 0.5), CSng(width * 0.5)) g.FillEllipse(Brushes.White, CSng(pt.X + (width * 0.4375)), CSng(pt.Y + (width * 0.1875)), CSng(width * 0.125), CSng(width * 0.125)) g.FillEllipse(Brushes.Black, CSng(pt.X + (width * 0.4375)), CSng(pt.Y + (width * 0.6875)), CSng(width * 0.125), CSng(width * 0.125)) If hasOutline Then g.DrawEllipse(Pens.Black, pt.X, pt.Y, width, width) End Sub
End Class </lang>