Some of the functions that I use to validate siteswaps on the Edge.
Use to parse any string, will return true if it is a valid siteswap, or false if not.
This function requires the Expand() function.
<?php
function Validate($SS)
{
// Normalise characterset
$FullCode=strtoupper($SS);
// 2 & 2t are the same thing for validation
$FullCode=str_replace('2T','2',$FullCode);
// Check syntax
if(preg_match('/^[0-9A-Z]+$/',$SS))
$Type='Vanilla';
elseif(preg_match('/^([0-9A-Z]*(\[[1-9A-Z]{2,}\])+[0-9A-Z]*)+$/',$SS))
$Type='Multiplex';
elseif(preg_match('/^(\([02468ACEGIKMOQSUWY]X?,[02468ACEGIKMOQSUWY]X?\))+\*?$/',$SS))
$Type='Synchronous';
elseif(preg_match('/^(\(([02468ACEGIKMOQSUWYX]X?|\[[2468ACEGIKMOQSUWYX]{2,}\]),([02468ACEGIKMOQSUWY]X?|\[[2468ACEGIKMOQSUWYX]{2,}\])\))+\*?$/',$SS))
$Type='Synchronous multiplex';
else
return false;
// Candidate throws
$Hex='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// If string is all one character, is valid siteswap
if(strlen($FullCode)<2 || preg_match('/^'.$FullCode[1].'+$/',$FullCode))
{
return true;
}
// If pattern contains parentheses it must be synchronous
$Synch=preg_match('/\(|\)/',$FullCode);
// If Synch SS ends with * mirror pairs of throws
if($Synch && substr($FullCode,-1)==='*')
$FullCode=Expand($FullCode);
// Start validation
$Values=[];
$Beat=[];
$Destination=[];
$a=0;
$b=strlen($FullCode);
$ThisChar;
$SynchOffset=0;
$ThisBeat=0;
$InMultiplex=false;
// Work through all characters in string, for each throw character populate 2 arrays:
// Values = The throw weight
// Beat = The beat the throw is made from
// also count number of beats in pattern
while($a<$b)
{
$ThisChar=$FullCode[$a];
if(ctype_alnum($ThisChar))
{
// Is a throw value
$Beat[]=$ThisBeat;
if($Synch && $FullCode[$a+1]==='X')
{
$Values[]=strpos($Hex,$ThisChar)+$SynchOffset;
++$a;
}
else
$Values[]=strpos($Hex,$ThisChar);
if($InMultiplex===false)
++$ThisBeat;
}
else
{
// Is multiplex or synchronous information
if($ThisChar==='[')
$InMultiplex=true;
if($ThisChar===']')
{
$InMultiplex=false;
++$ThisBeat;
}
if($ThisChar==='(' || $ThisChar===')')
$SynchOffset=1;
if($ThisChar===',')
$SynchOffset=-1;
}
++$a;
}
// Work through values, populate destination array with the beat that each throw lands on
$Period=$ThisBeat;
$b=count($Values);
for($a=0;$a<$b;++$a)
{
if($Values[$a]===0)
$Destination[$a]=$Beat[$a];
else
$Destination[$a]=($Beat[$a]+$Values[$a])%$Period;
}
// Initialise all beats in pattern as having nothing coming in or going out
$In=[];
$Out=[];
$b=$Period;
for($a=0;$a<$b;++$a)
{
$In[$a]=0;
$Out[$a]=0;
}
// Count up how many props are thrown (Out) & caught (In) on each beat
$b=count($Destination);
for($a=0;$a<$b;++$a)
{
if($Values[$a]!==0)
{
++$In[$Destination[$a]];
++$Out[$Beat[$a]];
}
}
// If number of props coming in exactly matches number of props going out on every beat, pattern is valid
return Implode(',',$In)===Implode(',',$Out);
}
?>
If $SS is of the form (a,b)(c,d)* convert to (a,b)(c,d)(b,a)(d,c).
<?php
function Expand($SS)
{
if(preg_match('/^(\(([02468ACEGI]X?|\[[02468ACEGI]{2,}\]),([02468ACEGI]X?|\[[02468ACEGI]{2,}\])\))+\*/i',$SS))
{
// Remove '*' from original code
$SS=substr($SS,0,-1);
// Create list of individual throws
$TempStr=substr($SS,1,-1);
$TempStr=preg_replace('/[\(\)]+/',',',$TempStr);
$Mirror=explode(',',$TempStr);
// Append original code with mirrored pairs of throws
for($a=0;$a<Count($Mirror);$a=$a+2)
{
$SS.='(';
$SS.=$Mirror[$a+1];
$SS.=',';
$SS.=$Mirror[$a];
$SS.=')';
}
}
return $SS;
}
?>
eg. shorten abcabcabc to abc. Also check to see if a synchronous siteswap can also be shortened further using * notation.
This function requires the Expand() function.
<?php
function Shorten($SS)
{
// Expand shortened synch siteswap if necessary
$SS=Expand($SS);
$c=strlen($SS);
$b=$c/2;
// Check for repetition starting from 1 character (smallest possible sequence)
// to half the length of the siteswap (largest possible sequence)
for($a=1;$a<$b;++$a)
{
// Check if siteswap can be exactly broken up into chunks of length $a
if($c%$a===0)
{
// Create array of strings all $a characters in length
$Segments=str_split($SS,$a);
// Check if all segments are equal
if(count(array_unique($Segments))===1)
{
// Smallest repeating sequence found, update siteswap & exit loop
$SS=$Segments[0];
break;
}
}
}
// Check if shortened siteswap is synchronous with an even number of pairs
// could possibly be shortened further using '*' notation
$Check1=substr($SS,0,strlen($SS)/2);
if(substr($Check1,-1)===')')
{
// Create shortened version, then expand to compare against result
$Check1.='*';
$Check2=Expand($Check1);
// If expanded check string matches result, then it is ok to shorten with '*'
if($SS===$Check2)
$SS=$Check1;
}
return $SS;
}
?>
This function returns true if two siteswaps are a rotation of each other, eg. abcd=dabc=cdab=bcda. Returns false if they are not, eg. abcd != acbd.
Both $SS1 and $SS2 need to have been parsed through Shorten() to ensure correct result.
This function requires the SortMultiplex() and Expand() functions.
<?php
function CheckRotation($SS1,$SS2)
{
// Expand shortened synch siteswaps if necessary
$SS1=Expand($SS1);
$SS2=Expand($SS2);
// Ensure multiplexes are in the same order
$SS1=SortMultiplex($SS1);
$SS2=SortMultiplex($SS2);
// If length of SS are equal & SS1 exists within SS2 repeated twice, patterns are rotations of each other
return (strlen($SS1)===strlen($SS2) && strpos($SS1,$SS2.$SS2)!==false);
}
?>
Judging from Edge record data the consensus is that throws within a multiplex should be written in descending order.
This function will sort all values within [square brackets] in reverse order. eg. abc[def]hij[klm] will become abc[fed]hij[mlk].
<?php
function SortMultiplex($SS)
{
$SS=preg_replace_callback(
'/\[([^\]]+)\]/',
function ($matches){
// Get contents of the multiplex
$str=$matches[1];
$Throws=[];
$a=0;
$b=strlen($str);
// Populate $Throws array with each individual throw
while($a<$b)
{
// Check for modified throws eg. 6x or 2t
if($str[$a+1]==='x' || $str[$a+1]==='X' || $str[$a+1]==='t' || $str[$a+1]==='T')
{
$Throws[]=$str[$a].$str[$a+1];
++$a;
}
else
$Throws[]=$str[$a];
++$a;
}
// Sort in reverse order
rsort($Throws);
return '['.implode('',$Throws).']';
},
$SS
);
return $SS;
}
?>