SuperCollider Forum
May 22, 2013, 07:02:21 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News: The SuperCollider forum is currently experiencing a rash of spambot registrations. New user requests may not be approved quickly as a result -- and if your email address looks like spam, it might not be approved at all. We are working to improve the security of the registration process, and to provide alternate means to contact the administrators to get a new account. Thanks for your patience.
 
   Home   Help Search Calendar Login Register  
Pages: [1]
  Print  
Author Topic: Nerdy color sorting fun  (Read 3793 times)
0 Members and 1 Guest are viewing this topic.
dewdrop_world
AdminGroup
Full Member
*

Karma: 9
Posts: 193



View Profile WWW
« on: December 12, 2008, 05:25:20 PM »

I'd been meaning to do this for awhile... when I was a kid, I was obsessed with a small program on the Apple II that had been printed in the magazine of the Puget Sound apple users group (I am really dating myself here). It did a two-dimensional bubble sort of colored blocks, ending up with these curved and tapered bands of color.

So I hacked it up in SuperCollider... basically just like I remember it Smiley

With 3600 blocks it will take quite some time to complete, but it's fascinating to watch as the random matrix slowly organizes itself from the outside in. A smaller matrix runs faster of course, but the bands are chunkier and not as pretty. If you get bored with it, just close the window and the routine will stop.

James

Code:
(
var blockSize = 10,
blocks = 60,
pixels = blockSize * blocks,
blockRect = Rect(0, 0, blockSize, blockSize),

brightness = { |color| color.red * color.green * color.blue },
colors = Array.fill(16, { Color.rand }).sort({ |a, b| brightness.(a) < brightness.(b) }),

matrix = Array.fill(blocks, { Array.fill(blocks, { colors.size.rand }) }),

sbounds = GUI.window.screenBounds,
w = GUI.window.new("HexaDecaColorDoubleBubbleSort",
Rect((sbounds.width - pixels) * 0.5, (sbounds.height - pixels * 0.5), pixels, pixels)),

views = matrix.collect({ |row, i|
row.collect({ |cell, j|
GUI.userView.new(w, Rect(i * blockSize, j * blockSize, blockSize, blockSize))
.relativeOrigin_(true)
.canFocus_(false)
.drawFunc_({ |view|
GUI.pen.color_(colors[matrix[i][j]])
.fillRect(blockRect)
});
});
}),

routine;

w.front;

routine = Routine({
var numSwaps = 1, temp,
// a bit tricky: I want to randomize whether it swaps
// horizontally first, or vertically
// so I put h-swap and v-swap functions in an array
// then, on each iteration, choose randomly which one to do first
swaps = [{ |i, j, k|
// horizontal swap
if((matrix[i][j] > matrix[i][k])) {
matrix[i].swap(j, k);
views[i][j].refresh;
views[i][k].refresh;
numSwaps = numSwaps + 1;
};
}, { |i, j, k|
// vertical swap
if(matrix[j][i] > matrix[k][i]) {
temp = matrix[j][i];
matrix[j][i] = matrix[k][i];
matrix[k][i] = temp;
views[j][i].refresh;
views[k][i].refresh;
numSwaps = numSwaps + 1;
};
}],
// another trick: going forward always causes a bias toward the bottom right
// so, we will scan forward first, then backward
fwdBackwd = Pseq(#[do, reverseDo], inf).asStream,
scanDirection;

while { numSwaps.debug("number of swaps last pass") > 0 } {
numSwaps = 0;
scanDirection = fwdBackwd.next;
blocks.perform(scanDirection, { |i|
(blocks-1).perform(scanDirection, { |j|
swaps[#[[0, 1], [1, 0]].choose].do({ |func|
func.value(i, j, j + 1);
});
0.01.wait;
});
});
};
"done".postln;
w.front; // no matter what I'm doing, I want this to pop up
}).play(AppClock);

w.onClose = { routine.stop };
)
Logged

dewdrop_world
AdminGroup
Full Member
*

Karma: 9
Posts: 193



View Profile WWW
« Reply #1 on: December 13, 2008, 09:39:24 AM »

Actually the userview/pen thing has some performance problems using Cocoa (OSX) gui objects. Here's another version using an empty statictext, setting the background color. It runs a lot faster in OSX.

James

Code:
(
var blockSize = 10,
blocks = 60,
pixels = blockSize * blocks,
blockRect = Rect(0, 0, blockSize, blockSize),

brightness = { |color| color.red * color.green * color.blue },
colors = Array.fill(16, { Color.rand }).sort({ |a, b| brightness.(a) < brightness.(b) }),

matrix = Array.fill(blocks, { Array.fill(blocks, { colors.size.rand }) }),

sbounds = GUI.window.screenBounds,
w = GUI.window.new("HexaDecaColorDoubleBubbleSort",
Rect((sbounds.width - pixels) * 0.5, (sbounds.height - pixels * 0.5), pixels, pixels)),

views = matrix.collect({ |row, i|
row.collect({ |cell, j|
GUI.staticText.new(w, Rect(i * blockSize, j * blockSize, blockSize, blockSize))
.background_(colors[matrix[i][j]]);
});
}),

updateColor = { |i, j|
views[i][j].background_(colors[matrix[i][j]]);
},

routine;

w.front;

routine = Routine({
var numSwaps = 1, temp,
// a bit tricky: I want to randomize whether it swaps
// horizontally first, or vertically
// so I put h-swap and v-swap functions in an array
// then, on each iteration, choose randomly which one to do first
swaps = [{ |i, j, k|
// horizontal swap
if((matrix[i][j] > matrix[i][k])) {
matrix[i].swap(j, k);
updateColor.(i, j);
updateColor.(i, k);
numSwaps = numSwaps + 1;
};
}, { |i, j, k|
// vertical swap
if(matrix[j][i] > matrix[k][i]) {
temp = matrix[j][i];
matrix[j][i] = matrix[k][i];
matrix[k][i] = temp;
updateColor.(j, i);
updateColor.(k, i);
numSwaps = numSwaps + 1;
};
}],
// another trick: going forward always causes a bias toward the bottom right
// so, we will scan forward first, then backward
fwdBackwd = Pseq(#[do, reverseDo], inf).asStream,
scanDirection;

while { numSwaps.debug("number of swaps last pass") > 0 } {
numSwaps = 0;
scanDirection = fwdBackwd.next;
blocks.perform(scanDirection, { |i|
(blocks-1).perform(scanDirection, { |j|
swaps[#[[0, 1], [1, 0]].choose].do({ |func|
func.value(i, j, j + 1);
});
0.01.wait;
});
});
};
"done".postln;
w.front; // no matter what I'm doing, I want this to pop up
}).play(AppClock);

w.onClose = { routine.stop };
)
Logged

Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC Valid XHTML 1.0! Valid CSS!