Here’s an updated version in which I rewrote the algorithm code. I checked it with several patterns and they all came out correct, so hopefully I have it right this time.
The new Flash app
Download the source files here.
I didn’t update the download ZIP file in the original post. So if you tire of the regular Euclidean patterns you can still download the old version and use those quirky ‘not quite right’ patterns. :-)
The difference
The difference between the old and new version can be seen in the outcome of the algorithm for a pattern of thirteen steps with five notes. The old version generates as outcome:
E(5, 13) = [x..x..x..x.x.]
while it should be:
E(5, 13) = [x..x.x..x.x..]
and the correct calculation broken down in iterations:
[x][x][x][x][x][.][.][.][.][.][.][.][.]
[x.][x.][x.][x.][x.][.][.][.]
[x..][x..][x..][x.][x.]
[x..x.][x..x.][x..]
It appears the old code stops one iteration too early: The wrong pattern is the same as the one before last iteration. Here’s the ActionScript code of the new version. It might be more compact and optimized, but I find it clearer to follow this way.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | package com.hisschemoller.utils { /** * @author Wouter Hisschemoller * (c) May 18, 2011 */ public class EuclidGenerator { private var _pattern : Vector.<Boolean> = new Vector.<Boolean>( ); public function EuclidGenerator ( total : int, hits : int ) { if ( hits >= total || hits == 1 || hits == 0 ) { _pattern = new Vector.<Boolean>( ); if ( hits >= total ) { for ( var i : int = 0; i < total; i ++ ) { _pattern.push( true ); } } else if ( total == 1 ) { _pattern.push( hits == 1 ); } else { for ( i = 0; i < total; i ++ ) { _pattern.push( false ); } } return; } var bigArray : Vector.<Vector.<Boolean>> = new Vector.<Vector.<Boolean>>( ); for ( i = 0; i < hits; i ++ ) { var boolArray : Vector.<Boolean> = new Vector.<Boolean>( ); boolArray.push( true ); bigArray.push( boolArray ); } var smallArray : Vector.<Vector.<Boolean>> = new Vector.<Vector.<Boolean>>( ); for ( i = 0; i < ( total - hits ); i ++ ) { boolArray = new Vector.<Boolean>( ); boolArray.push( false ); smallArray.push( boolArray ); } _pattern = bjorklund( bigArray, smallArray ); } public function get pattern () : Vector.<Boolean> { return _pattern; } private function bjorklund ( bigArray : Vector.<Vector.<Boolean>>, smallArray : Vector.<Vector.<Boolean>> ) : Vector.<Boolean> { /** Done, flatten arrays. */ if ( smallArray.length <= 1 ) { var resultList : Vector.<Boolean> = new Vector.<Boolean>( ); for ( var i : int = 0; i < bigArray.length; i ++ ) { for ( var j : int = 0; j < bigArray[ i ].length; j ++ ) { resultList.push( bigArray[ i ][ j ] ); } } for ( i = 0; i < smallArray.length; i ++ ) { for ( j = 0; j < smallArray[ i ].length; j ++ ) { resultList.push( smallArray[i][j] ); } } return resultList; } var fullRounds : int = Math.floor( smallArray.length / bigArray.length ); for ( i = 0; i < fullRounds; i ++ ) { for ( j = 0; j < bigArray.length; j ++ ) { var sourceBoolArray : Vector.<Boolean> = smallArray[0]; for ( var k : int = 0; k < sourceBoolArray.length; k ++ ) { bigArray[j].push( sourceBoolArray[k] ); } smallArray.splice( 0, 1 ); } } var remainder : int = smallArray.length % bigArray.length; for ( i = 0; i < remainder; i ++ ) { sourceBoolArray = smallArray[0]; for ( k = 0; k < sourceBoolArray.length; k ++ ) { bigArray[i].push( sourceBoolArray[k] ); } smallArray.splice( 0, 1 ); } /** Split result in two new arrays. */ var newBigArray : Vector.<Vector.<Boolean>> = new Vector.<Vector.<Boolean>>( ); var newSmallArray : Vector.<Vector.<Boolean>> = new Vector.<Vector.<Boolean>>( ); for ( i = 0; i < bigArray.length; i ++ ) { if ( remainder == 0 ) { newBigArray.push( bigArray[i] ); } else { if ( i < remainder ) { newBigArray.push( bigArray[i] ); } else { newSmallArray.push( bigArray[i] ); } } } return bjorklund( newBigArray, newSmallArray ); } } } |