Vibrating rectangles

From Rosetta Code
Vibrating rectangles 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.
Task
  1. Draw at least 20 rectangles with a common center, to be more precise, the circumcenter of all the rectangles must coincide. None of the rectangles must touch or intersect any other rectangle.
  2. Animate the colours of the rectangles by fading in the colour from the outermost rectangle to the innermost.
  3. The animation loop can continue for a definite number of iterations or forever.

Create Vibrating rectangles

C[edit]

Dimensions of the rectangles, their number and the animation delay can be configured. Requires the WinBGIm library.

 
/*Abhishek Ghosh, 15th September 2018*/
 
#include<graphics.h>
 
void vibratingRectangles(int winWidth,int winHeight,int leastLength,int leastWidth,int num, int msec)
{
int color = 1,i,x = winWidth/2, y = winHeight/2;
 
while(!kbhit()){
setcolor(color++);
for(i=num;i>0;i--){
rectangle(x - i*leastLength,y - i*leastWidth,x + i*leastLength,y + i*leastWidth);
delay(msec);
}
 
if(color>MAXCOLORS){
color = 1;
}
}
}
 
int main()
{
initwindow(1000,1000,"Vibrating Rectangles...");
 
vibratingRectangles(1000,1000,30,15,20,500);
 
closegraph();
 
return 0;
}
 

Go[edit]

This uses Go's 'image' packages in its standard library to create an animated GIF.

When played this is somewhat similar to the Python entry except that it uses a 7 (rather than 6) color palette and repeats indefinitely.

Although the .gif works fine in Firefox it might not do so in EOG due to optimizations made during its creation. If so, then the following ImageMagick command should fix it:

  $ convert vibrating.gif -coalesce vibrating2.gif
  $ eog vibrating2.gif
package main
 
import (
"image"
"image/color"
"image/gif"
"log"
"os"
)
 
var (
black = color.RGBA{0, 0, 0, 255}
red = color.RGBA{255, 0, 0, 255}
green = color.RGBA{0, 255, 0, 255}
blue = color.RGBA{0, 0, 255, 255}
magenta = color.RGBA{255, 0, 255, 255}
cyan = color.RGBA{0, 255, 255, 255}
yellow = color.RGBA{255, 255, 0, 255}
white = color.RGBA{255, 255, 255, 255}
)
 
var palette = []color.Color{red, green, blue, magenta, cyan, yellow, white, black}
 
func hline(img *image.Paletted, x1, y, x2 int, ci uint8) {
for ; x1 <= x2; x1++ {
img.SetColorIndex(x1, y, ci)
}
}
 
func vline(img *image.Paletted, x, y1, y2 int, ci uint8) {
for ; y1 <= y2; y1++ {
img.SetColorIndex(x, y1, ci)
}
}
 
func setBackgroundColor(img *image.Paletted, w, h int, ci uint8) {
for x := 0; x < w; x++ {
for y := 0; y < h; y++ {
img.SetColorIndex(x, y, ci)
}
}
}
 
func drawRectangle(img *image.Paletted, x1, y1, x2, y2 int, ci uint8) {
hline(img, x1, y1, x2, ci)
hline(img, x1, y2, x2, ci)
vline(img, x1, y1, y2, ci)
vline(img, x2, y1, y2, ci)
}
 
func main() {
const nframes = 140
const delay = 10 // 100ms
width, height := 500, 500
anim := gif.GIF{LoopCount: nframes}
rect := image.Rect(0, 0, width, height)
for c := uint8(0); c < 7; c++ {
for f := 0; f < 20; f++ {
img := image.NewPaletted(rect, palette)
setBackgroundColor(img, width, height, 7) // black background
for r := 0; r < 20; r++ {
ix := c
if r < f {
ix = (ix + 1) % 7
}
x := width * (r + 1) / 50
y := height * (r + 1) / 50
w := width - x
h := height - y
drawRectangle(img, x, y, w, h, ix)
}
anim.Delay = append(anim.Delay, delay)
anim.Image = append(anim.Image, img)
}
}
file, err := os.Create("vibrating.gif")
if err != nil {
log.Fatal(err)
}
defer file.Close()
if err2 := gif.EncodeAll(file, &anim); err != nil {
log.Fatal(err2)
}
}

JavaScript[edit]

HTML you'll need for testing

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Vibrating rectangles</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>
            body{background-color:black;text-align:center;margin-top:150px}
        </style>
        <script src="vibRects.js"></script>
    </head>
    <body onload="start()">
        <div id='wnd'></div>
    </body>
</html>
 
const SIZE = 400, WAIT = .025;
class VibRects {
constructor() {
this.wait = WAIT;
this.colorIndex = 0;
this.dimension = 5;
this.lastTime = 0;
this.accumulator = 0;
this.deltaTime = 1 / 60;
this.colors = ["#ff0000", "#ff8000", "#ffff00", "#80ff00", "#00ff00", "#00ff80",
"#00ffff", "#0080ff", "#0000ff", "#8000ff", "#ff00ff", "#ff0080"];
this.canvas = document.createElement('canvas');
this.canvas.width = SIZE;
this.canvas.height = SIZE;
const d = document.getElementById("wnd");
d.appendChild(this.canvas);
this.ctx = this.canvas.getContext('2d');
for(let d = this.dimension; d < SIZE / 2; d += 10) {
this.draw("#404040", d);
}
}
draw(clr, d) {
this.ctx.strokeStyle = clr;
this.ctx.beginPath();
this.ctx.moveTo(d, d);
this.ctx.lineTo(SIZE - d, d);
this.ctx.lineTo(SIZE - d, SIZE - d);
this.ctx.lineTo(d, SIZE - d);
this.ctx.closePath();
this.ctx.stroke();
}
update(dt) {
if((this.wait -= dt) < 0) {
this.draw(this.colors[this.colorIndex], this.dimension);
this.wait = WAIT;
if((this.dimension += 10) > SIZE / 2) {
this.dimension = 5;
this.colorIndex = (this.colorIndex + 1) % this.colors.length;
}
}
}
start() {
this.loop = (time) => {
this.accumulator += (time - this.lastTime) / 1000;
while(this.accumulator > this.deltaTime) {
this.accumulator -= this.deltaTime;
this.update(Math.min(this.deltaTime));
}
this.lastTime = time;
requestAnimationFrame(this.loop);
}
this.loop(0);
}
}
function start() {
const vibRects = new VibRects();
vibRects.start();
}
 

Perl[edit]

Using the core module Time::HiRres to get sub-second sleep

Translation of: Perl 6
use utf8;
binmode STDOUT, ":utf8";
use Time::HiRes qw(sleep);
 
%r = ('tl' => qw<>, 'tr' => qw<>, 'h' => qw<>, 'v' => qw<>, 'bl' => qw<>, 'br' => qw<>);
@colors = ("\e[1;31m", "\e[1;32m", "\e[1;33m", "\e[1;34m", "\e[1;35m", "\e[1;36m");
 
print "\e[?25l"; # hide the cursor
 
$SIG{INT} = sub { print "\e[0H\e[0J\e[?25h"; exit; }; # clean up on exit
 
while (1) {
@c = palette() unless $n % 16;
rect($_, 31-$_) for 0..15;
display(@vibe);
sleep .20;
push @c, $c[0]; shift @c;
$n++;
}
 
sub palette {
my @c = sort { -1 + 2*int(rand 2) } @colors;
($c[0], $c[1], $c[2]) x 12;
}
 
sub rect {
my ($b, $e) = @_;
my $c = $c[$b % @c];
my @bb = ($c.$r{tl}, (($r{h})x($e-$b-1)), $r{tr}."\e[0m");
my @ee = ($c.$r{bl}, (($r{h})x($e-$b-1)), $r{br}."\e[0m");
$vibe[$b][$_] = shift @bb for $b .. $e;
$vibe[$e][$_] = shift @ee for $b .. $e;
$vibe[$_][$b] = $vibe[$_][$e] = $c.$r{v}."\e[0m" for $b+1 .. $e-1;
}
 
sub display {
my(@rect) = @_;
print "\e[0H\e[0J\n\n";
for my $row (@rect) {
print "\t\t\t";
print $_ // ' ' for @$row;
print "\n";
}
}

Perl 6[edit]

Works with: Rakudo version 2018.06

Ok. The task description is essentially non-existent. In looking at the reference implementation (Ring) it seems like we are supposed to draw a series of concentric rectangles and then alter the colors step-wise. No actual vibration apparent.

Could fire up a GUI but WTH, let's try it at a command line with ANSI.

Draws a series of concentric rectangles then rotates through the color palette. Every three seconds, chooses new random palette colors and reverses rotation direction.

# box drawing characters
my %r = :tl<>, :h<>, :tr<>, :v<>, :bl<>, :br<>;
 
my @colors = « \e[1;31m \e[1;94m \e[1;33m \e[1;35m \e[1;36m \e[1;32m \e[1;34m »;
 
# color palette
my @c = flat @colors[0] xx 12, @colors[3] xx 12, @colors[2] xx 12;
 
print "\e[?25l"; # hide the cursor
 
signal(SIGINT).tap: {
print "\e[0H\e[0J\e[?25h"; # clean up on exit
exit;
}
 
my $rot = 1;
 
my @vibe;
 
loop {
rect($_, 31-$_) for ^15;
display @vibe;
@c.=rotate($rot);
if ++$ %% 30 {
@c = |@colors.pick(3);
@c = sort(flat @c xx 12);
$rot *= -1;
}
sleep .1;
}
 
sub rect ($b, $e) {
@vibe[$b;$b..$e] = @c[$b % @c]~%r<tl>, |((%r<h>) xx ($e - $b - 1)), %r<tr>~"\e[0m";
@vibe[$e;$b..$e] = @c[$b % @c]~%r<bl>, |((%r<h>) xx ($e - $b - 1)), %r<br>~"\e[0m";
($b ^..^ $e).map: { @vibe[$_;$b] = @vibe[$_;$e] = @c[$b % @c]~%r<v>~"\e[0m" }
}
 
sub display (@rect) {
print "\e[0H\e[0J\n\n";
for @rect -> @row {
print "\t\t\t";
print $_ // ' ' for @row;
print "\n";
}
}

See: Vibrating rectangles (.gif image)

Python[edit]

import turtle
from itertools import cycle
from time import sleep
 
def rect(t, x, y):
x2, y2 = x/2, y/2
t.setpos(-x2, -y2)
t.pendown()
for pos in [(-x2, y2), (x2, y2), (x2, -y2), (-x2, -y2)]:
t.goto(pos)
t.penup()
 
def rects(t, colour, wait_between_rect=0.1):
for x in range(550, 0, -25):
t.color(colour)
rect(t, x, x*.75)
sleep(wait_between_rect)
 
tl=turtle.Turtle()
screen=turtle.Screen()
screen.setup(620,620)
screen.bgcolor('black')
screen.title('Rosetta Code Vibrating Rectangles')
tl.pensize(3)
tl.speed(0)
tl.penup()
tl.ht()
colours = 'red green blue orange white yellow'.split()
for colour in cycle(colours):
rects(tl, colour)
sleep(0.5)
 
Output:

Hmm, maybe this?

Ring[edit]

 
# Project : Vibrating rectangles
 
Load "guilib.ring"
 
color1 = new qcolor() { setrgb( 255,0,0,255 ) }
pen1 = new qpen() { setcolor(color1) setwidth(2) }
 
color2 = new qcolor() { setrgb( 0,255,0,255 ) }
pen2 = new qpen() { setcolor(color2) setwidth(2) }
 
color3 = new qcolor() { setrgb( 0,0,255,255 ) }
pen3 = new qpen() { setcolor(color3) setwidth(2) }
 
penArray = [pen1, pen2, pen3]
penNbr = 1
 
New qapp
{
win1 = new qwidget()
{
setwindowtitle("Drawing using QPixMap")
setgeometry(100,100,500,500)
label1 = new qlabel(win1)
{
setgeometry(10,10,500,500)
settext("")
}
Canvas = new qlabel(win1)
{
MonaLisa = new qPixMap2( 500,500)
color = new qcolor(){ setrgb(255,0,0,255) }
 
daVinci = new qpainter()
{
begin(MonaLisa)
}
setpixmap(MonaLisa)
}
nCounter = 0
oTimer = new qTimer(win1) {
setinterval(500)
settimeoutevent("DrawCounter()")
start()
}
show()
}
exec()
}
DrawCounter()
 
func DrawCounter()
nCounter++
if nCounter < 15
Draw(penArray[penNbr])
elseif nCounter % 15 = 0
nCounter = 0
penNbr++
if penNbr > 3
penNbr = 1
ok
Draw(penArray[penNbr])
ok
return
 
Func Draw(pen1)
daVinci.setpen(penArray[penNbr])
daVinci.drawrect(50+nCounter*10, 50+nCounter*10, 300-nCounter*20, 300-nCounter*20)
Canvas.setpixmap(MonaLisa)
win1.show()
return
 

Output:

Vibrating rectangles