Cantor set
Draw Cantor set. See details: Cantor set
ALGOL 68
<lang algol68>BEGIN
# draw a Cantor Set using ASCII # INT lines = 5; # number of lines for the set # # we must choose the line width so that the width of each segment is # # divisible by 3 ( except for the final line where the segment width will # # be 1 ) # INT set width = 3 ^ ( lines - 1 ); [ set width ]CHAR set; # start with a complete line # FOR i TO set width DO set[ i ] := "#" OD; print( ( set, newline ) ); # repeatedly modify the line, replacing the middle third of each segment # # with blanks # INT segment width := set width OVER 3; WHILE segment width > 0 DO INT set pos := 1; WHILE set pos < ( set width - segment width ) DO set pos +:= segment width; FOR char pos FROM set pos TO ( set pos + segment width ) - 1 DO set[ char pos ] := " " OD; set pos +:= segment width OD; print( ( set, newline ) ); segment width OVERAB 3 OD
END</lang>
- Output:
################################################################################# ########################### ########################### ######### ######### ######### ######### ### ### ### ### ### ### ### ### # # # # # # # # # # # # # # # #
ALGOL W
Based on the Algol 68 sample. <lang algolw>begin
% draw a Cantor Set using ASCII % integer LINES; % number of lines for the set % integer setWidth; % width of each line of the set % % we must choose the line width so that the width of each segment is % % divisible by 3 ( except for the final line where the segment width will % % be 1 ) % LINES := 5; setWidth := round( 3 ** ( LINES - 1 ) ); begin % start new block so the array can have computed bounds % logical array set ( 1 :: setWidth ); integer segmentWidth; % start with a complete line % for i := 1 until setWidth do set( i ) := true; segmentWidth := setWidth; for l := 1 until LINES do begin % print the latest line, all lines start with a "#" % write( "#" ); for i := 2 until setWidth do writeon( if set( i ) then "#" else " " ); % modify the line, replacing the middle third of each segment % % with blanks, unless this was the last line % if l < LINES then begin integer setPos; segmentWidth := segmentWidth div 3; setPos := 1; while setPos < ( setWidth - segmentWidth ) do begin setPos := setPos + segmentWidth; for charPos := setPos until ( setPos + segmentWidth ) - 1 do set( charPos ) := false; setPos := setPos + segmentWidth end while_setPos_in_range ; end if_l_lt_LINES end for_l end
end.</lang>
- Output:
################################################################################# ########################### ########################### ######### ######### ######### ######### ### ### ### ### ### ### ### ### # # # # # # # # # # # # # # # #
AppleScript
<lang applescript>-- cantor :: [(Bool, Int)] -> [(Bool, Int)] on cantor(xs)
script go on |λ|(tpl) set {bln, n} to tpl if bln and 1 < n then set m to n div 3 {{true, m}, {false, m}, {true, m}} else {tpl} end if end |λ| end script concatMap(go, xs)
end cantor
-- TEST ---------------------------------------------------
on run
cantorLines(5)
end run
-- cantorLines :: Int -> String
on cantorLines(n)
unlines(map(my showCantor, take(n, ¬ iterate(cantor, Template:True, 3 ^ (n - 1)))))
end cantorLines
-- showCantor :: [(Bool, Int)] -> String
on showCantor(xs)
script go on |λ|(tpl) set {bln, n} to tpl if bln then set c to character id 9608 else set c to space end if replicate(n, c) end |λ| end script concat(map(go, xs))
end showCantor
-- GENERIC ------------------------------------------------
-- concat :: a -> [a] -- concat :: [String] -> String on concat(xs)
set lng to length of xs if 0 < lng and string is class of (item 1 of xs) then set acc to "" else set acc to {} end if repeat with i from 1 to lng set acc to acc & item i of xs end repeat acc
end concat
-- concatMap :: (a -> [b]) -> [a] -> [b] on concatMap(f, xs)
set lng to length of xs set acc to {} tell mReturn(f) repeat with i from 1 to lng set acc to acc & |λ|(item i of xs, i, xs) end repeat end tell return acc
end concatMap
-- 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
-- Lift 2nd class handler function into 1st class script wrapper -- mReturn :: First-class m => (a -> b) -> m (a -> b) on mReturn(f)
if class of f is script then f else script property |λ| : f end script end if
end mReturn
-- iterate :: (a -> a) -> a -> Gen [a] on iterate(f, x)
script property v : missing value property g : mReturn(f)'s |λ| on |λ|() if missing value is v then set v to x else set v to g(v) end if return v end |λ| end script
end iterate
-- replicate :: Int -> String -> String
on replicate(n, s)
set out to "" if n < 1 then return out set dbl to s 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
-- take :: Int -> [a] -> [a]
-- take :: Int -> String -> String
on take(n, xs)
set c to class of xs if list is c then if 0 < n then items 1 thru min(n, length of xs) of xs else {} end if else if string is c then if 0 < n then text 1 thru min(n, length of xs) of xs else "" end if else if script is c then set ys to {} repeat with i from 1 to n set v to xs's |λ|() if missing value is v then return ys else set end of ys to v end if end repeat return ys else missing value end if
end take
-- unlines :: [String] -> String on unlines(xs)
set {dlm, my text item delimiters} to ¬ {my text item delimiters, linefeed} set str to xs as text set my text item delimiters to dlm str
end unlines</lang>
- Output:
█████████████████████████████████████████████████████████████████████████████████ ███████████████████████████ ███████████████████████████ █████████ █████████ █████████ █████████ ███ ███ ███ ███ ███ ███ ███ ███ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
AWK
<lang AWK>
- syntax: GAWK -f CANTOR_SET.AWK
- converted from C
BEGIN {
WIDTH = 81 HEIGHT = 5 for (i=0; i<HEIGHT; ++i) { for (j=0; j<WIDTH; ++j) { lines[i][j] = "*" } } cantor(0,WIDTH,1) for (i=0; i<HEIGHT; ++i) { for (j=0; j<WIDTH; ++j) { printf("%s",lines[i][j]) } printf("\n") } exit(0)
} function cantor(start,leng,indx, i,j,seg) {
seg = int(leng/3) if (seg == 0) { return } for (i=indx; i<HEIGHT; ++i) { for (j=start+seg; j<start+seg*2; ++j) { lines[i][j] = " " } } cantor(start,seg,indx+1) cantor(start+seg*2,seg,indx+1)
} </lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
C
<lang c>#include <stdio.h>
- define WIDTH 81
- define HEIGHT 5
char lines[HEIGHT][WIDTH];
void init() {
int i, j; for (i = 0; i < HEIGHT; ++i) { for (j = 0; j < WIDTH; ++j) lines[i][j] = '*'; }
}
void cantor(int start, int len, int index) {
int i, j, seg = len / 3; if (seg == 0) return; for (i = index; i < HEIGHT; ++i) { for (j = start + seg; j < start + seg * 2; ++j) lines[i][j] = ' '; } cantor(start, seg, index + 1); cantor(start + seg * 2, seg, index + 1);
}
void print() {
int i, j; for (i = 0; i < HEIGHT; ++i) { for (j = 0; j < WIDTH; ++j) printf("%c", lines[i][j]); printf("\n"); }
}
int main() {
init(); cantor(0, WIDTH, 1); print(); return 0;
}</lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
C#
<lang csharp>using System;
namespace CantorSet {
class Program { const int WIDTH = 81; const int HEIGHT = 5; private static char[,] lines = new char[HEIGHT, WIDTH];
static Program() { for (int i = 0; i < HEIGHT; i++) { for (int j = 0; j < WIDTH; j++) { lines[i, j] = '*'; } } }
private static void Cantor(int start, int len, int index) { int seg = len / 3; if (seg == 0) return; for (int i = index; i < HEIGHT; i++) { for (int j = start + seg; j < start + seg * 2; j++) { lines[i, j] = ' '; } } Cantor(start, seg, index + 1); Cantor(start + seg * 2, seg, index + 1); }
static void Main(string[] args) { Cantor(0, WIDTH, 1); for (int i = 0; i < HEIGHT; i++) { for (int j = 0; j < WIDTH; j++) { Console.Write(lines[i,j]); } Console.WriteLine(); } } }
}</lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
D
<lang d>import std.stdio;
enum WIDTH = 81; enum HEIGHT = 5;
char[WIDTH*HEIGHT] lines;
void cantor(int start, int len, int index) {
int seg = len / 3; if (seg == 0) return; for (int i=index; i<HEIGHT; i++) { for (int j=start+seg; j<start+seg*2; j++) { int pos = i*WIDTH + j; lines[pos] = ' '; } } cantor(start, seg, index+1); cantor(start+seg*2, seg, index+1);
}
void main() {
// init lines[] = '*';
// calculate cantor(0, WIDTH, 1);
// print for (int i=0; i<HEIGHT; i++) { int beg = WIDTH * i; writeln(lines[beg..beg+WIDTH]); }
}</lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
Factor
<lang factor>USING: grouping.extras io kernel math sequences sequences.repeating ; IN: rosetta-code.cantor-set
CONSTANT: width 81 CONSTANT: depth 5
- cantor ( n -- seq )
dup 0 = [ drop { 0 1 } ] [ 1 - cantor [ 3 / ] map dup [ 2/3 + ] map append ] if ;
! Produces a sequence of lengths from a Cantor set, depending on ! width. Even indices are solid; odd indices are blank. ! e.g. 2 cantor gaps -> { 9 9 9 27 9 9 9 } !
- gaps ( seq -- seq )
[ width * ] map [ - abs ] 2clump-map ;
- print-cantor ( n -- )
cantor gaps [ even? "#" " " ? swap repeat ] map-index concat print ;
depth <iota> [ print-cantor ] each</lang>
- Output:
################################################################################# ########################### ########################### ######### ######### ######### ######### ### ### ### ### ### ### ### ### # # # # # # # # # # # # # # # #
Go
<lang go>package main
import "fmt"
const (
width = 81 height = 5
)
var lines [height][width]byte
func init() {
for i := 0; i < height; i++ { for j := 0; j < width; j++ { lines[i][j] = '*' } }
}
func cantor(start, len, index int) {
seg := len / 3 if seg == 0 { return } for i := index; i < height; i++ { for j := start + seg; j < start + 2 * seg; j++ { lines[i][j] = ' ' } } cantor(start, seg, index + 1) cantor(start + seg * 2, seg, index + 1)
}
func main() {
cantor(0, width, 1) for _, line := range lines { fmt.Println(string(line[:])) }
}</lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
Haskell
(Functional version)
<lang haskell>cantor :: [(Bool, Int)] -> [(Bool, Int)] cantor xs =
let go (bln, n) | bln && 1 < n = [(True, m), (False, m), (True, m)] | otherwise = [(bln, n)] where m = quot n 3 in xs >>= go
cantorLines :: Int -> String cantorLines n =
unlines $ showCantor <$> take n (iterate cantor [(True, 3 ^ (n - 1))])
showCantor :: [(Bool, Int)] -> String showCantor =
concatMap (\(bln, n) -> replicate n (if bln then '*' else ' '))
main :: IO () main = putStrLn $ cantorLines 5</lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
Or, using strings for the model as well as the display:
<lang haskell>cantor :: [String] -> [String] cantor xs =
let go s | ('█' == head s) = [t, replicate m ' ', t] | otherwise = [s] where m = quot (length s) 3 t = take m s in xs >>= go
cantorLines :: Int -> String cantorLines n =
unlines $ concat <$> take n (iterate cantor [replicate (3 ^ (n - 1)) '█'])
main :: IO () main = putStrLn $ cantorLines 5</lang>
- Output:
█████████████████████████████████████████████████████████████████████████████████ ███████████████████████████ ███████████████████████████ █████████ █████████ █████████ █████████ ███ ███ ███ ███ ███ ███ ███ ███ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
Java
<lang java>public class App {
private static final int WIDTH = 81; private static final int HEIGHT = 5;
private static char[][] lines; static { lines = new char[HEIGHT][WIDTH]; for (int i = 0; i < HEIGHT; i++) { for (int j = 0; j < WIDTH; j++) { lines[i][j] = '*'; } } }
private static void cantor(int start, int len, int index) { int seg = len / 3; if (seg == 0) return; for (int i = index; i < HEIGHT; i++) { for (int j = start + seg; j < start + seg * 2; j++) { lines[i][j] = ' '; } } cantor(start, seg, index + 1); cantor(start + seg * 2, seg, index + 1); }
public static void main(String[] args) { cantor(0, WIDTH, 1); for (int i = 0; i < HEIGHT; i++) { for (int j = 0; j < WIDTH; j++) { System.out.print(lines[i][j]); } System.out.println(); } }
} </lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
JavaScript
(Functional version)
<lang JavaScript>(() => {
'use strict';
const main = () => {
// cantor :: [(Bool, Int)] -> [(Bool, Int)] const cantor = xs => { const go = ([bln, n]) => bln && 1 < n ? (() => { const lng = Math.floor(n / 3); return [ [true, lng], [false, lng], [true, lng] ] })() : [ [bln, n] ]; return concatMap(go, xs); };
// cantorLines :: Int -> String const cantorLines = n => unlines( map(showCantor, take(n, iterate( cantor, [ [true, Math.pow(3, n - 1)] ] ) ) ) );
// showCantor :: [(Bool, Int)] -> String const showCantor = xs => concat(map( ([bln, n]) => replicate(n, bln ? '*' : ' '), xs ));
console.log( cantorLines(5) ); };
// GENERIC FUNCTIONS ----------------------------------
// concat :: a -> [a] // concat :: [String] -> String const concat = xs => 0 < xs.length ? (() => { const unit = 'string' !== typeof xs[0] ? ( [] ) : ; return unit.concat.apply(unit, xs); })() : [];
// concatMap :: (a -> [b]) -> [a] -> [b] const concatMap = (f, xs) => xs.reduce((a, x) => a.concat(f(x)), []);
// iterate :: (a -> a) -> a -> Gen [a] function* iterate(f, x) { let v = x; while (true) { yield(v); v = f(v); } }
// map :: (a -> b) -> [a] -> [b] const map = (f, xs) => xs.map(f);
// replicate :: Int -> String -> String const replicate = (n, s) => s.repeat(n);
// take :: Int -> [a] -> [a] // take :: Int -> String -> String const take = (n, xs) => 'GeneratorFunction' !== xs.constructor.constructor.name ? ( xs.slice(0, n) ) : [].concat.apply([], Array.from({ length: n }, () => { const x = xs.next(); return x.done ? [] : [x.value]; }));
// unlines :: [String] -> String const unlines = xs => xs.join('\n');
// MAIN --- return main();
})();</lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
Kotlin
Simple terminal drawing. <lang scala>// Version 1.2.31
const val WIDTH = 81 const val HEIGHT = 5
val lines = List(HEIGHT) { CharArray(WIDTH) { '*' } }
fun cantor(start: Int, len: Int, index: Int) {
val seg = len / 3 if (seg == 0) return for (i in index until HEIGHT) { for (j in start + seg until start + seg * 2) lines[i][j] = ' ' } cantor(start, seg, index + 1) cantor(start + seg * 2, seg, index + 1)
}
fun main(args: Array<String>) {
cantor(0, WIDTH, 1) lines.forEach { println(it) }
}</lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
Lua
<lang lua>local WIDTH = 81 local HEIGHT = 5 local lines = {}
function cantor(start, length, index)
-- must be local, or only one side will get calculated local seg = math.floor(length / 3) if 0 == seg then return nil end
-- remove elements that are not in the set for it=0, HEIGHT - index do i = index + it for jt=0, seg - 1 do j = start + seg + jt pos = WIDTH * i + j lines[pos] = ' ' end end
-- left side cantor(start, seg, index + 1) -- right side cantor(start + seg * 2, seg, index + 1) return nil
end
-- initialize the lines for i=0, WIDTH * HEIGHT do
lines[i] = '*'
end
-- calculate cantor(0, WIDTH, 1)
-- print the result sets for i=0, HEIGHT-1 do
beg = WIDTH * i for j=beg, beg+WIDTH-1 do if j <= WIDTH * HEIGHT then io.write(lines[j]) end end print()
end</lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
Modula-2
<lang modula2>MODULE Cantor; FROM Terminal IMPORT Write,WriteLn,ReadChar;
CONST
WIDTH = 81; HEIGHT = 5;
VAR
lines : ARRAY[0..HEIGHT] OF ARRAY[0..WIDTH] OF CHAR;
PROCEDURE Init; VAR i,j : CARDINAL; BEGIN
FOR i:=0 TO HEIGHT DO FOR j:=0 TO WIDTH DO lines[i,j] := '*' END END
END Init;
PROCEDURE Cantor(start,len,index : CARDINAL); VAR i,j,seg : CARDINAL; BEGIN
seg := len DIV 3; IF seg=0 THEN RETURN END; FOR i:=index TO HEIGHT-1 DO j := start+seg; FOR j:=start+seg TO start+seg*2-1 DO lines[i,j] := ' ' END END; Cantor(start, seg, index+1); Cantor(start+seg*2, seg, index+1)
END Cantor;
PROCEDURE Print; VAR i,j : CARDINAL; BEGIN
FOR i:=0 TO HEIGHT-1 DO FOR j:=0 TO WIDTH-1 DO Write(lines[i,j]) END; WriteLn END
END Print;
BEGIN
Init; Cantor(0,WIDTH,1); Print;
ReadChar;
END Cantor.</lang>
Perl
<lang Perl>use feature 'say';
sub cantor {
my($height) = @_; my $width = 3 ** ($height - 1);
my @lines = ('#' x $width) x $height;
sub trim_middle_third { my($len, $start, $index) = @_; my $seg = int $len / 3 or return;
for $i ( $index .. $height - 1 ) { for $j ( 0 .. $seg - 1 ) { substr @lines[$i], $start + $seg + $j, 1, ' '; } }
trim_middle_third( $seg, $start + $_, $index + 1 ) for 0, $seg * 2; }
trim_middle_third( $width, 0, 1 ); @lines;
}
say for cantor(5);</lang>
- Output:
################################################################################# ########################### ########################### ######### ######### ######### ######### ### ### ### ### ### ### ### ### # # # # # # # # # # # # # # # #
Perl 6
<lang perl6>sub cantor ( Int $height ) {
my $width = 3 ** ($height - 1);
my @lines = ( "\c[FULL BLOCK]" x $width ) xx $height;
my sub _trim_middle_third ( $len, $start, $index ) { my $seg = $len div 3 or return;
for ( $index ..^ $height ) X ( 0 ..^ $seg ) -> ( $i, $j ) { @lines[$i].substr-rw( $start + $seg + $j, 1 ) = ' '; }
_trim_middle_third( $seg, $start + $_, $index + 1 ) for 0, $seg * 2; }
_trim_middle_third( $width, 0, 1 ); return @lines;
}
.say for cantor(5);</lang>
- Output:
█████████████████████████████████████████████████████████████████████████████████ ███████████████████████████ ███████████████████████████ █████████ █████████ █████████ █████████ ███ ███ ███ ███ ███ ███ ███ ███ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
Phix
Based on Algol 68, but even simpler, shorter, and sweeter! <lang Phix>integer n = 5,
w = power(3,n-1), len = w
string line = repeat('#',w)&"\n"
while 1 do
puts(1,line) if len=1 then exit end if len /= 3 integer pos = 1 while pos<(w-len) do pos += len line[pos..pos+len-1] = ' ' pos += len end while
end while</lang>
- Output:
################################################################################# ########################### ########################### ######### ######### ######### ######### ### ### ### ### ### ### ### ### # # # # # # # # # # # # # # # #
Python
Imperative
<lang python>WIDTH = 81 HEIGHT = 5
lines=[] def cantor(start, len, index):
seg = len / 3 if seg == 0: return None for it in xrange(HEIGHT-index): i = index + it for jt in xrange(seg): j = start + seg + jt pos = i * WIDTH + j lines[pos] = ' ' cantor(start, seg, index + 1) cantor(start + seg * 2, seg, index + 1) return None
lines = ['*'] * (WIDTH*HEIGHT) cantor(0, WIDTH, 1)
for i in xrange(HEIGHT):
beg = WIDTH * i print .join(lines[beg : beg+WIDTH])</lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
Functional
<lang python>from itertools import (chain, islice, repeat)
- cantor :: [(Bool, Int)] -> [(Bool, Int)]
def cantor(xs):
def go(tpl): (bln, n) = tpl m = n // 3 return [ (True, m), (False, m), (True, m) ] if bln and (1 < n) else [tpl] return concatMap(go)(xs)
- cantorLines :: Int -> String
def cantorLines(n):
return '\n'.join( showCantor(x) for x in islice( iterate(cantor)( [(True, 3 ** (n - 1))] ), n ) )
- showCantor :: [(Bool, Int)] -> String
def showCantor(xs):
return .join( concatMap(lambda tpl: repeat('*' if tpl[0] else ' ', tpl[1]))( xs ) )
- main :: IO ()
def main():
print ( cantorLines(5) )
- GENERIC -------------------------------------------------------------
- concatMap :: (a -> [b]) -> [a] -> [b]
def concatMap(f):
return lambda xs: list( chain.from_iterable( map(f, xs) ) )
- iterate :: (a -> a) -> a -> Gen [a]
def iterate(f):
def go(x): v = x while True: yield(v) v = f(v) return lambda x: go(x)
- MAIN ---
main()</lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
Racket
<lang racket>#lang racket/base
- {trans|Kotlin}}
(define current-width (make-parameter 81))
(define current-height (make-parameter 5))
(define (Cantor_set (w (current-width)) (h (current-height)))
(define lines (build-list h (λ (_) (make-bytes w (char->integer #\#))))) (define (cantor start len index) (let* ((seg (quotient len 3)) (seg-start (+ start seg)) (seg-end (+ seg-start seg))) (unless (zero? seg) (for* ((i (in-range index h)) (j (in-range seg-start seg-end))) (bytes-set! (list-ref lines i) j (char->integer #\space))) (cantor start seg (add1 index)) (cantor seg-end seg (add1 index))))) (cantor 0 w 1) lines)
(module+ main
(for-each displayln (Cantor_set)))
</lang>
- Output:
********************************************************************************* *************************** *************************** ********* ********* ********* ********* *** *** *** *** *** *** *** *** * * * * * * * * * * * * * * * *
REXX
<lang rexx>/*REXX program displays an ASCII diagram of a Canter Set as a set of (character) lines. */ w= linesize() /*obtain the width of the display term.*/ if w==0 then w=81 /*Can't obtain width? Use the default.*/
do lines=0; _=3**lines /*calculate powers of three (# lines).*/ if _>w then leave /*Too large? We passed the max value. */ #=_ /*this value of a width─of─line is OK. */ end /*lines*/ /* [↑] calculate a useable line width.*/
w= # /*use the (last) useable line width. */ $= copies('■', #) /*populate the display line with blocks*/
do j=0 until #==0 /*show Cantor set as a line of chars. */ if j>0 then do k=#+1 by #+# to w /*skip 1st line blanking.*/ $=overlay(left(, #), $, k) /*blank parts of a line. */ end /*j*/ say $ /*display a line of the Cantor Set. */ #= # % 3 /*the part (thirds) to be blanked out. */ end /*j*/ /*stick a fork in it, we're all done. */</lang>
This REXX program makes use of linesize REXX program (or BIF) which is used to determine the screen width (or linesize) of the terminal (console).
Some REXXes don't have this BIF, so the linesize.rex REXX program is included here ──► LINESIZE.REX.
- output when using the default size of the terminal width of 100:
(Shown at half size.)
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
- output when using the default size of the terminal width of 250:
(Shown at half size.)
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■■■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
Ring
<lang ring>
- Project : Cantor set
load "guilib.ring" paint = null
new qapp
{ win1 = new qwidget() { setwindowtitle("") setgeometry(100,100,800,600) label1 = new qlabel(win1) { setgeometry(10,10,800,600) settext("") } new qpushbutton(win1) { setgeometry(150,500,100,30) settext("draw") setclickevent("draw()") } show() } exec() }
func draw
p1 = new qpicture() color = new qcolor() { setrgb(0,0,255,255) } pen = new qpen() { setcolor(color) setwidth(10) } paint = new qpainter() { begin(p1) setpen(pen)
cantor(10,20,600)
endpaint() } label1 { setpicture(p1) show() } return
func cantor(x,y,lens)
if lens >= 10 paint.drawline(x,y,x+lens,y) y = y + 20 cantor(x,y,floor(lens/3)) cantor(x+floor(lens*2/3),y,floor(lens/3)) ok
</lang> Output image:
Scala
Imperative Programming (Q&D)
<lang Scala>object CantorSetQD extends App {
val (width, heigth) = (81, 5)
val lines = Seq.fill[Array[Char]](heigth)(Array.fill[Char](width)('*'))
def cantor(start: Int, len: Int, index: Int) { val seg = len / 3
println(start, len, index)
if (seg != 0) { for (i <- index until heigth; j <- (start + seg) until (start + seg * 2)) lines(i)(j) = ' '
cantor(start, seg, index + 1) cantor(start + seg * 2, seg, index + 1) } }
cantor(0, width, 1) lines.foreach(l => println(l.mkString))
}</lang>
- Output:
See it in running in your browser by (JavaScript)
or by Scastie (JVM).
Functional Programming (Recommended)
<lang Scala>object CantorSetFP extends App {
val (width, heigth) = (81, 5)
def lines = (1 to heigth).map(_ => (0 until width).toSet)
def cantorSet(pre: Seq[Set[Int]], start: Int, len: Int, index: Int): Seq[Set[Int]] = { val seg = len / 3
def cantorSet1(pre: Seq[Set[Int]], start: Int, index: Int): Seq[Set[Int]] = { def elementsStuffing(pre: Set[Int], start: Int): Set[Int] = pre -- ((start + seg) until (start + seg * 2))
for (n <- 0 until heigth) yield if (index to heigth contains n) elementsStuffing(pre(n), start) else pre(n) }
if (seg == 0) pre else { def version0 = cantorSet1(pre, start, index) def version1 = cantorSet(cantorSet1(pre, start, index), start, seg, index + 1)
cantorSet(version1, start + seg * 2, seg, index + 1) } }
def output: Seq[Set[Int]] = cantorSet(lines, 0, width, 1)
println( output.map(l => (0 to width).map(pos => if (l contains pos) '*' else ' ').mkString) .mkString("\n"))
}</lang>
- Output:
See it in running in your browser by (JavaScript)
or by Scastie (JVM).
Sidef
<lang ruby>func cantor (height) {
var width = 3**(height - 1) var lines = height.of { "\N{FULL BLOCK}" * width }
func trim_middle_third (len, start, index) { var seg = (len // 3) || return()
for i, j in ((index ..^ height) ~X (0 ..^ seg)) { lines[i].replace!(Regex("^.{#{start + seg + j}}\\K."), ' ') }
[0, 2*seg].each { |k| trim_middle_third(seg, start + k, index + 1) } }
trim_middle_third(width, 0, 1) return lines
}
cantor(5).each { .say }</lang>
- Output:
█████████████████████████████████████████████████████████████████████████████████ ███████████████████████████ ███████████████████████████ █████████ █████████ █████████ █████████ ███ ███ ███ ███ ███ ███ ███ ███ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
zkl
<lang zkl>const WIDTH=81, HEIGHT=5; var lines=HEIGHT.pump(List,List.createLong(WIDTH,"\U2588;").copy); // full block
fcn cantor(start,len,index){
(seg:=len/3) or return(); foreach i,j in ([index..HEIGHT-1], [start + seg .. start + seg*2 - 1]){ lines[i][j]=" "; } cantor(start, seg, index + 1); cantor(start + seg*2, seg, index + 1);
}(0,WIDTH,1);
lines.pump(Console.println,"concat");</lang>
- Output:
█████████████████████████████████████████████████████████████████████████████████ ███████████████████████████ ███████████████████████████ █████████ █████████ █████████ █████████ ███ ███ ███ ███ ███ ███ ███ ███ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █