Pascal records and Mathematica programming












10












$begingroup$


Background:




  • "experienced" Pascal-programmer (DOS-era, never got into OOP)

  • proud owner of Mathematica ver 11.2

  • have used Mathematica for years to do my share of number crunching and plotting to produce material for my university courses (as well as for Math.SE :-)


Next task:



I need to add a few things to my Mathematica repertoire. The immediate goal is to build the necessary Mathematica functions to produce animated GIFs like



enter image description here



That is, animated sequences of moves on a Rubik cube. The shown sequence of moves cyclically permutes the positions of $3$ corner pieces. The GIF is included here to give the general idea, and also to prove that I know enough to code this :-)



Currently the animation is achieved by manipulating a variable descriptively named vertexlist that contains the 3D-positions of all the eight corners of all the small moving parts. It is clear that to produce the desired animations, I simply need to manipulate the contents of this variable, and have Mathematica Show the cube in all the intermediate states in sequence.



The snake in the paradise is that currently vertexlist is, in old-timer-speak, a global variable. I probably can do everything I need in the immediate future that way, but I have reached a point, where that feels A) unprofessional, B) inefficient. For example, in a classroom setting I surely want to have several different Rubik's cubes of varying sizes, and in various current states. To that end I need a data structure not unlike a Pascal record (similar to struct in C), say (I know this is unsyntactic, because the value of a field cannot really be used as a limit of an array, but we can safely ignore that here I think):



cube=RECORD
size:2..5;
vertexlist: ARRAY[1..size,1..size,1..size,1..8] OF...
...(* information about which vertices form a polygon of which color *)
END;


With that taken care of I can then easily code functions roughly like
MicroRotation[c_, Axes_, Layer_, Angle_], where c would be the cube I want to modify.



How do I achieve something like that type declaration in Mathematica? I know that in Mathematica everything really is a list, and that I can simply define my objects with a new list header like JyrkisRubikCube (ok, that would be kludgy, but anyway). But doing that would not really help here! For I need my code to refer to and modify the individual fields of the data structure. If I use a List, I guess I can, using the freedom built into Mathematica's lists just assume that the first entry is the size, the second is the vertexlist et cetera. Is that really the only way to go? Is it the recommended way? Having descriptive names for the fields of the record would, at the very least, help me if I want to return to this project a few years down the road...



Searching the site gave some promising looking hits:





  • Here is a similar question about C structs. There is a lot of material in the answers, but at first reading they appeared to be a bit too high level to me. More about that below.

  • In loc.linked Leonid Shifrin referred to this thread in SO for something similar.


I will keep studying those. If I try and use Association as described by Szabolcs how do I:




  1. create/declare a variable of the prescribed type,

  2. access the chosen field of a variable of this type, and

  3. modify the value of (a component of) the chosen field of a variable of this type?


I realize that this question may be too broad to be answered well in the limited space available here, but I also appreciate pointers and links. Even a key buzzword might do. Given that outside academia (and in spite of the best efforts of Borland) Pascal never got much traction, probably eplaining why my searches did not produce anything very useful.



Edit: The posts I found leave me with the impression that using Association creates a data structure that is very kludgy to modify. Consider the following snippet from my current notebook. This function
rotates the layer number v (an integer in the range from $1$ to size)
by an angle given by the variable x



 rotateX[v_, x_] := Module[{i, j, k, t},
m = {{1, 0, 0}, {0, Cos[x], -Sin[x]}, {0, Sin[x], Cos[x]}};
For[i = 1, i < size + 1, i++,
For[j = 1, j < size + 1, j++,
For[k = 1, k < size + 1, k++,
If[Floor[vertexlist[[i, j, k]][[1]][[1]]] == v,
For[t = 1, t < 9, t++,
vertexlist[[i, j, k]][[t]] =
m.(vertexlist[[i, j, k]][[t]] - {0, center, center}) + {0,
center, center}
]]]]]]


You see that I modify the components of the global vertexlist in the 4-fold loop according to whether the small part is currently in the layer being rotated.



I need a way of modifying not the global vertexlist but the vertexlist of a cube of my choice to be passed as a third parameter to rotateX. Something like rotateX[c_,x_,cube_] that will modify cube.vertexlist instead of vertexlist, where cube is a data structure that has at least size and vertexlist as fields.




Is there a way of doing this other than using, say, cube[[2]], everywhere in places of the more natural cube.vertexlist?






One more animated sequence of moves. I am using ListAnimate to generate these. I chose to do eight frames per a quarter turn, so an animation of 8 quarter turns has 64 frames. The sequence of moves below also cyclically permutes the positions of three small cubes. This time those small cubes are on the faces of the big cube. Two of those small cubes show a white face and one of them shows a blue face. Because one white cube moved to the place initially occupied by another white cube, visually the result looks like a blue and a white piece traded places, but, in fact, it is a 3-cycle. Meaning, that you need to perform the sequence of moves three times to return the cube to its initial state. The algebra of permutations plays out in a way that 3-cycles are simple to produce. Ask me, if you want to know more :-)



enter image description here










share|improve this question











$endgroup$








  • 1




    $begingroup$
    The tags are fine.
    $endgroup$
    – Szabolcs
    Apr 12 at 11:27






  • 2




    $begingroup$
    What is your main goal here? Is it to work with a Rubik's cube as a combinatorial object? If so, then things like continuous spatial coordinates are irrelevant for analysing the moves. They are only relevant for vsualization. Or are you focusing specifically on the visualization and on creating animations?
    $endgroup$
    – Szabolcs
    Apr 12 at 11:33






  • 1




    $begingroup$
    Do take a look at this demonstration, which seems to have all of this implemented. demonstrations.wolfram.com/RubiksCube The author is an expert Mathematica programmer and I would put trust in his design.
    $endgroup$
    – Szabolcs
    Apr 12 at 11:34








  • 1




    $begingroup$
    @JyrkiLahtonen Indeed, I would suggest to use Association wrapped by a head to indicate the "class". So an instance of the class would look like X = JyrkisRubikCube[Association[...]]. Then you can use TagSetDelayed for defining and overloading methods for this class. A field/property "foo" of X can then accessed with X[[1]][["foo"]] and set with X[[1]][["foo"]] = bar. It is not like you have a fixed set of allowed keys in the association; fields can be created and deleted (KeyDrop) dynamically. But I guess that's what comes closed to what you ask for.
    $endgroup$
    – Henrik Schumacher
    Apr 12 at 11:38












  • $begingroup$
    @Szabolcs Visualization is exactly the goal here. I plan to use this to make a few concepts from a first course on groups more concrete to a bunch of people at freshman level. I won't be ignoring the algebra, because I teach algebra for living. Of course, this is also just for fun.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 11:38
















10












$begingroup$


Background:




  • "experienced" Pascal-programmer (DOS-era, never got into OOP)

  • proud owner of Mathematica ver 11.2

  • have used Mathematica for years to do my share of number crunching and plotting to produce material for my university courses (as well as for Math.SE :-)


Next task:



I need to add a few things to my Mathematica repertoire. The immediate goal is to build the necessary Mathematica functions to produce animated GIFs like



enter image description here



That is, animated sequences of moves on a Rubik cube. The shown sequence of moves cyclically permutes the positions of $3$ corner pieces. The GIF is included here to give the general idea, and also to prove that I know enough to code this :-)



Currently the animation is achieved by manipulating a variable descriptively named vertexlist that contains the 3D-positions of all the eight corners of all the small moving parts. It is clear that to produce the desired animations, I simply need to manipulate the contents of this variable, and have Mathematica Show the cube in all the intermediate states in sequence.



The snake in the paradise is that currently vertexlist is, in old-timer-speak, a global variable. I probably can do everything I need in the immediate future that way, but I have reached a point, where that feels A) unprofessional, B) inefficient. For example, in a classroom setting I surely want to have several different Rubik's cubes of varying sizes, and in various current states. To that end I need a data structure not unlike a Pascal record (similar to struct in C), say (I know this is unsyntactic, because the value of a field cannot really be used as a limit of an array, but we can safely ignore that here I think):



cube=RECORD
size:2..5;
vertexlist: ARRAY[1..size,1..size,1..size,1..8] OF...
...(* information about which vertices form a polygon of which color *)
END;


With that taken care of I can then easily code functions roughly like
MicroRotation[c_, Axes_, Layer_, Angle_], where c would be the cube I want to modify.



How do I achieve something like that type declaration in Mathematica? I know that in Mathematica everything really is a list, and that I can simply define my objects with a new list header like JyrkisRubikCube (ok, that would be kludgy, but anyway). But doing that would not really help here! For I need my code to refer to and modify the individual fields of the data structure. If I use a List, I guess I can, using the freedom built into Mathematica's lists just assume that the first entry is the size, the second is the vertexlist et cetera. Is that really the only way to go? Is it the recommended way? Having descriptive names for the fields of the record would, at the very least, help me if I want to return to this project a few years down the road...



Searching the site gave some promising looking hits:





  • Here is a similar question about C structs. There is a lot of material in the answers, but at first reading they appeared to be a bit too high level to me. More about that below.

  • In loc.linked Leonid Shifrin referred to this thread in SO for something similar.


I will keep studying those. If I try and use Association as described by Szabolcs how do I:




  1. create/declare a variable of the prescribed type,

  2. access the chosen field of a variable of this type, and

  3. modify the value of (a component of) the chosen field of a variable of this type?


I realize that this question may be too broad to be answered well in the limited space available here, but I also appreciate pointers and links. Even a key buzzword might do. Given that outside academia (and in spite of the best efforts of Borland) Pascal never got much traction, probably eplaining why my searches did not produce anything very useful.



Edit: The posts I found leave me with the impression that using Association creates a data structure that is very kludgy to modify. Consider the following snippet from my current notebook. This function
rotates the layer number v (an integer in the range from $1$ to size)
by an angle given by the variable x



 rotateX[v_, x_] := Module[{i, j, k, t},
m = {{1, 0, 0}, {0, Cos[x], -Sin[x]}, {0, Sin[x], Cos[x]}};
For[i = 1, i < size + 1, i++,
For[j = 1, j < size + 1, j++,
For[k = 1, k < size + 1, k++,
If[Floor[vertexlist[[i, j, k]][[1]][[1]]] == v,
For[t = 1, t < 9, t++,
vertexlist[[i, j, k]][[t]] =
m.(vertexlist[[i, j, k]][[t]] - {0, center, center}) + {0,
center, center}
]]]]]]


You see that I modify the components of the global vertexlist in the 4-fold loop according to whether the small part is currently in the layer being rotated.



I need a way of modifying not the global vertexlist but the vertexlist of a cube of my choice to be passed as a third parameter to rotateX. Something like rotateX[c_,x_,cube_] that will modify cube.vertexlist instead of vertexlist, where cube is a data structure that has at least size and vertexlist as fields.




Is there a way of doing this other than using, say, cube[[2]], everywhere in places of the more natural cube.vertexlist?






One more animated sequence of moves. I am using ListAnimate to generate these. I chose to do eight frames per a quarter turn, so an animation of 8 quarter turns has 64 frames. The sequence of moves below also cyclically permutes the positions of three small cubes. This time those small cubes are on the faces of the big cube. Two of those small cubes show a white face and one of them shows a blue face. Because one white cube moved to the place initially occupied by another white cube, visually the result looks like a blue and a white piece traded places, but, in fact, it is a 3-cycle. Meaning, that you need to perform the sequence of moves three times to return the cube to its initial state. The algebra of permutations plays out in a way that 3-cycles are simple to produce. Ask me, if you want to know more :-)



enter image description here










share|improve this question











$endgroup$








  • 1




    $begingroup$
    The tags are fine.
    $endgroup$
    – Szabolcs
    Apr 12 at 11:27






  • 2




    $begingroup$
    What is your main goal here? Is it to work with a Rubik's cube as a combinatorial object? If so, then things like continuous spatial coordinates are irrelevant for analysing the moves. They are only relevant for vsualization. Or are you focusing specifically on the visualization and on creating animations?
    $endgroup$
    – Szabolcs
    Apr 12 at 11:33






  • 1




    $begingroup$
    Do take a look at this demonstration, which seems to have all of this implemented. demonstrations.wolfram.com/RubiksCube The author is an expert Mathematica programmer and I would put trust in his design.
    $endgroup$
    – Szabolcs
    Apr 12 at 11:34








  • 1




    $begingroup$
    @JyrkiLahtonen Indeed, I would suggest to use Association wrapped by a head to indicate the "class". So an instance of the class would look like X = JyrkisRubikCube[Association[...]]. Then you can use TagSetDelayed for defining and overloading methods for this class. A field/property "foo" of X can then accessed with X[[1]][["foo"]] and set with X[[1]][["foo"]] = bar. It is not like you have a fixed set of allowed keys in the association; fields can be created and deleted (KeyDrop) dynamically. But I guess that's what comes closed to what you ask for.
    $endgroup$
    – Henrik Schumacher
    Apr 12 at 11:38












  • $begingroup$
    @Szabolcs Visualization is exactly the goal here. I plan to use this to make a few concepts from a first course on groups more concrete to a bunch of people at freshman level. I won't be ignoring the algebra, because I teach algebra for living. Of course, this is also just for fun.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 11:38














10












10








10


3



$begingroup$


Background:




  • "experienced" Pascal-programmer (DOS-era, never got into OOP)

  • proud owner of Mathematica ver 11.2

  • have used Mathematica for years to do my share of number crunching and plotting to produce material for my university courses (as well as for Math.SE :-)


Next task:



I need to add a few things to my Mathematica repertoire. The immediate goal is to build the necessary Mathematica functions to produce animated GIFs like



enter image description here



That is, animated sequences of moves on a Rubik cube. The shown sequence of moves cyclically permutes the positions of $3$ corner pieces. The GIF is included here to give the general idea, and also to prove that I know enough to code this :-)



Currently the animation is achieved by manipulating a variable descriptively named vertexlist that contains the 3D-positions of all the eight corners of all the small moving parts. It is clear that to produce the desired animations, I simply need to manipulate the contents of this variable, and have Mathematica Show the cube in all the intermediate states in sequence.



The snake in the paradise is that currently vertexlist is, in old-timer-speak, a global variable. I probably can do everything I need in the immediate future that way, but I have reached a point, where that feels A) unprofessional, B) inefficient. For example, in a classroom setting I surely want to have several different Rubik's cubes of varying sizes, and in various current states. To that end I need a data structure not unlike a Pascal record (similar to struct in C), say (I know this is unsyntactic, because the value of a field cannot really be used as a limit of an array, but we can safely ignore that here I think):



cube=RECORD
size:2..5;
vertexlist: ARRAY[1..size,1..size,1..size,1..8] OF...
...(* information about which vertices form a polygon of which color *)
END;


With that taken care of I can then easily code functions roughly like
MicroRotation[c_, Axes_, Layer_, Angle_], where c would be the cube I want to modify.



How do I achieve something like that type declaration in Mathematica? I know that in Mathematica everything really is a list, and that I can simply define my objects with a new list header like JyrkisRubikCube (ok, that would be kludgy, but anyway). But doing that would not really help here! For I need my code to refer to and modify the individual fields of the data structure. If I use a List, I guess I can, using the freedom built into Mathematica's lists just assume that the first entry is the size, the second is the vertexlist et cetera. Is that really the only way to go? Is it the recommended way? Having descriptive names for the fields of the record would, at the very least, help me if I want to return to this project a few years down the road...



Searching the site gave some promising looking hits:





  • Here is a similar question about C structs. There is a lot of material in the answers, but at first reading they appeared to be a bit too high level to me. More about that below.

  • In loc.linked Leonid Shifrin referred to this thread in SO for something similar.


I will keep studying those. If I try and use Association as described by Szabolcs how do I:




  1. create/declare a variable of the prescribed type,

  2. access the chosen field of a variable of this type, and

  3. modify the value of (a component of) the chosen field of a variable of this type?


I realize that this question may be too broad to be answered well in the limited space available here, but I also appreciate pointers and links. Even a key buzzword might do. Given that outside academia (and in spite of the best efforts of Borland) Pascal never got much traction, probably eplaining why my searches did not produce anything very useful.



Edit: The posts I found leave me with the impression that using Association creates a data structure that is very kludgy to modify. Consider the following snippet from my current notebook. This function
rotates the layer number v (an integer in the range from $1$ to size)
by an angle given by the variable x



 rotateX[v_, x_] := Module[{i, j, k, t},
m = {{1, 0, 0}, {0, Cos[x], -Sin[x]}, {0, Sin[x], Cos[x]}};
For[i = 1, i < size + 1, i++,
For[j = 1, j < size + 1, j++,
For[k = 1, k < size + 1, k++,
If[Floor[vertexlist[[i, j, k]][[1]][[1]]] == v,
For[t = 1, t < 9, t++,
vertexlist[[i, j, k]][[t]] =
m.(vertexlist[[i, j, k]][[t]] - {0, center, center}) + {0,
center, center}
]]]]]]


You see that I modify the components of the global vertexlist in the 4-fold loop according to whether the small part is currently in the layer being rotated.



I need a way of modifying not the global vertexlist but the vertexlist of a cube of my choice to be passed as a third parameter to rotateX. Something like rotateX[c_,x_,cube_] that will modify cube.vertexlist instead of vertexlist, where cube is a data structure that has at least size and vertexlist as fields.




Is there a way of doing this other than using, say, cube[[2]], everywhere in places of the more natural cube.vertexlist?






One more animated sequence of moves. I am using ListAnimate to generate these. I chose to do eight frames per a quarter turn, so an animation of 8 quarter turns has 64 frames. The sequence of moves below also cyclically permutes the positions of three small cubes. This time those small cubes are on the faces of the big cube. Two of those small cubes show a white face and one of them shows a blue face. Because one white cube moved to the place initially occupied by another white cube, visually the result looks like a blue and a white piece traded places, but, in fact, it is a 3-cycle. Meaning, that you need to perform the sequence of moves three times to return the cube to its initial state. The algebra of permutations plays out in a way that 3-cycles are simple to produce. Ask me, if you want to know more :-)



enter image description here










share|improve this question











$endgroup$




Background:




  • "experienced" Pascal-programmer (DOS-era, never got into OOP)

  • proud owner of Mathematica ver 11.2

  • have used Mathematica for years to do my share of number crunching and plotting to produce material for my university courses (as well as for Math.SE :-)


Next task:



I need to add a few things to my Mathematica repertoire. The immediate goal is to build the necessary Mathematica functions to produce animated GIFs like



enter image description here



That is, animated sequences of moves on a Rubik cube. The shown sequence of moves cyclically permutes the positions of $3$ corner pieces. The GIF is included here to give the general idea, and also to prove that I know enough to code this :-)



Currently the animation is achieved by manipulating a variable descriptively named vertexlist that contains the 3D-positions of all the eight corners of all the small moving parts. It is clear that to produce the desired animations, I simply need to manipulate the contents of this variable, and have Mathematica Show the cube in all the intermediate states in sequence.



The snake in the paradise is that currently vertexlist is, in old-timer-speak, a global variable. I probably can do everything I need in the immediate future that way, but I have reached a point, where that feels A) unprofessional, B) inefficient. For example, in a classroom setting I surely want to have several different Rubik's cubes of varying sizes, and in various current states. To that end I need a data structure not unlike a Pascal record (similar to struct in C), say (I know this is unsyntactic, because the value of a field cannot really be used as a limit of an array, but we can safely ignore that here I think):



cube=RECORD
size:2..5;
vertexlist: ARRAY[1..size,1..size,1..size,1..8] OF...
...(* information about which vertices form a polygon of which color *)
END;


With that taken care of I can then easily code functions roughly like
MicroRotation[c_, Axes_, Layer_, Angle_], where c would be the cube I want to modify.



How do I achieve something like that type declaration in Mathematica? I know that in Mathematica everything really is a list, and that I can simply define my objects with a new list header like JyrkisRubikCube (ok, that would be kludgy, but anyway). But doing that would not really help here! For I need my code to refer to and modify the individual fields of the data structure. If I use a List, I guess I can, using the freedom built into Mathematica's lists just assume that the first entry is the size, the second is the vertexlist et cetera. Is that really the only way to go? Is it the recommended way? Having descriptive names for the fields of the record would, at the very least, help me if I want to return to this project a few years down the road...



Searching the site gave some promising looking hits:





  • Here is a similar question about C structs. There is a lot of material in the answers, but at first reading they appeared to be a bit too high level to me. More about that below.

  • In loc.linked Leonid Shifrin referred to this thread in SO for something similar.


I will keep studying those. If I try and use Association as described by Szabolcs how do I:




  1. create/declare a variable of the prescribed type,

  2. access the chosen field of a variable of this type, and

  3. modify the value of (a component of) the chosen field of a variable of this type?


I realize that this question may be too broad to be answered well in the limited space available here, but I also appreciate pointers and links. Even a key buzzword might do. Given that outside academia (and in spite of the best efforts of Borland) Pascal never got much traction, probably eplaining why my searches did not produce anything very useful.



Edit: The posts I found leave me with the impression that using Association creates a data structure that is very kludgy to modify. Consider the following snippet from my current notebook. This function
rotates the layer number v (an integer in the range from $1$ to size)
by an angle given by the variable x



 rotateX[v_, x_] := Module[{i, j, k, t},
m = {{1, 0, 0}, {0, Cos[x], -Sin[x]}, {0, Sin[x], Cos[x]}};
For[i = 1, i < size + 1, i++,
For[j = 1, j < size + 1, j++,
For[k = 1, k < size + 1, k++,
If[Floor[vertexlist[[i, j, k]][[1]][[1]]] == v,
For[t = 1, t < 9, t++,
vertexlist[[i, j, k]][[t]] =
m.(vertexlist[[i, j, k]][[t]] - {0, center, center}) + {0,
center, center}
]]]]]]


You see that I modify the components of the global vertexlist in the 4-fold loop according to whether the small part is currently in the layer being rotated.



I need a way of modifying not the global vertexlist but the vertexlist of a cube of my choice to be passed as a third parameter to rotateX. Something like rotateX[c_,x_,cube_] that will modify cube.vertexlist instead of vertexlist, where cube is a data structure that has at least size and vertexlist as fields.




Is there a way of doing this other than using, say, cube[[2]], everywhere in places of the more natural cube.vertexlist?






One more animated sequence of moves. I am using ListAnimate to generate these. I chose to do eight frames per a quarter turn, so an animation of 8 quarter turns has 64 frames. The sequence of moves below also cyclically permutes the positions of three small cubes. This time those small cubes are on the faces of the big cube. Two of those small cubes show a white face and one of them shows a blue face. Because one white cube moved to the place initially occupied by another white cube, visually the result looks like a blue and a white piece traded places, but, in fact, it is a 3-cycle. Meaning, that you need to perform the sequence of moves three times to return the cube to its initial state. The algebra of permutations plays out in a way that 3-cycles are simple to produce. Ask me, if you want to know more :-)



enter image description here







programming animation data-structures






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Apr 13 at 4:47







Jyrki Lahtonen

















asked Apr 12 at 11:22









Jyrki LahtonenJyrki Lahtonen

523412




523412








  • 1




    $begingroup$
    The tags are fine.
    $endgroup$
    – Szabolcs
    Apr 12 at 11:27






  • 2




    $begingroup$
    What is your main goal here? Is it to work with a Rubik's cube as a combinatorial object? If so, then things like continuous spatial coordinates are irrelevant for analysing the moves. They are only relevant for vsualization. Or are you focusing specifically on the visualization and on creating animations?
    $endgroup$
    – Szabolcs
    Apr 12 at 11:33






  • 1




    $begingroup$
    Do take a look at this demonstration, which seems to have all of this implemented. demonstrations.wolfram.com/RubiksCube The author is an expert Mathematica programmer and I would put trust in his design.
    $endgroup$
    – Szabolcs
    Apr 12 at 11:34








  • 1




    $begingroup$
    @JyrkiLahtonen Indeed, I would suggest to use Association wrapped by a head to indicate the "class". So an instance of the class would look like X = JyrkisRubikCube[Association[...]]. Then you can use TagSetDelayed for defining and overloading methods for this class. A field/property "foo" of X can then accessed with X[[1]][["foo"]] and set with X[[1]][["foo"]] = bar. It is not like you have a fixed set of allowed keys in the association; fields can be created and deleted (KeyDrop) dynamically. But I guess that's what comes closed to what you ask for.
    $endgroup$
    – Henrik Schumacher
    Apr 12 at 11:38












  • $begingroup$
    @Szabolcs Visualization is exactly the goal here. I plan to use this to make a few concepts from a first course on groups more concrete to a bunch of people at freshman level. I won't be ignoring the algebra, because I teach algebra for living. Of course, this is also just for fun.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 11:38














  • 1




    $begingroup$
    The tags are fine.
    $endgroup$
    – Szabolcs
    Apr 12 at 11:27






  • 2




    $begingroup$
    What is your main goal here? Is it to work with a Rubik's cube as a combinatorial object? If so, then things like continuous spatial coordinates are irrelevant for analysing the moves. They are only relevant for vsualization. Or are you focusing specifically on the visualization and on creating animations?
    $endgroup$
    – Szabolcs
    Apr 12 at 11:33






  • 1




    $begingroup$
    Do take a look at this demonstration, which seems to have all of this implemented. demonstrations.wolfram.com/RubiksCube The author is an expert Mathematica programmer and I would put trust in his design.
    $endgroup$
    – Szabolcs
    Apr 12 at 11:34








  • 1




    $begingroup$
    @JyrkiLahtonen Indeed, I would suggest to use Association wrapped by a head to indicate the "class". So an instance of the class would look like X = JyrkisRubikCube[Association[...]]. Then you can use TagSetDelayed for defining and overloading methods for this class. A field/property "foo" of X can then accessed with X[[1]][["foo"]] and set with X[[1]][["foo"]] = bar. It is not like you have a fixed set of allowed keys in the association; fields can be created and deleted (KeyDrop) dynamically. But I guess that's what comes closed to what you ask for.
    $endgroup$
    – Henrik Schumacher
    Apr 12 at 11:38












  • $begingroup$
    @Szabolcs Visualization is exactly the goal here. I plan to use this to make a few concepts from a first course on groups more concrete to a bunch of people at freshman level. I won't be ignoring the algebra, because I teach algebra for living. Of course, this is also just for fun.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 11:38








1




1




$begingroup$
The tags are fine.
$endgroup$
– Szabolcs
Apr 12 at 11:27




$begingroup$
The tags are fine.
$endgroup$
– Szabolcs
Apr 12 at 11:27




2




2




$begingroup$
What is your main goal here? Is it to work with a Rubik's cube as a combinatorial object? If so, then things like continuous spatial coordinates are irrelevant for analysing the moves. They are only relevant for vsualization. Or are you focusing specifically on the visualization and on creating animations?
$endgroup$
– Szabolcs
Apr 12 at 11:33




$begingroup$
What is your main goal here? Is it to work with a Rubik's cube as a combinatorial object? If so, then things like continuous spatial coordinates are irrelevant for analysing the moves. They are only relevant for vsualization. Or are you focusing specifically on the visualization and on creating animations?
$endgroup$
– Szabolcs
Apr 12 at 11:33




1




1




$begingroup$
Do take a look at this demonstration, which seems to have all of this implemented. demonstrations.wolfram.com/RubiksCube The author is an expert Mathematica programmer and I would put trust in his design.
$endgroup$
– Szabolcs
Apr 12 at 11:34






$begingroup$
Do take a look at this demonstration, which seems to have all of this implemented. demonstrations.wolfram.com/RubiksCube The author is an expert Mathematica programmer and I would put trust in his design.
$endgroup$
– Szabolcs
Apr 12 at 11:34






1




1




$begingroup$
@JyrkiLahtonen Indeed, I would suggest to use Association wrapped by a head to indicate the "class". So an instance of the class would look like X = JyrkisRubikCube[Association[...]]. Then you can use TagSetDelayed for defining and overloading methods for this class. A field/property "foo" of X can then accessed with X[[1]][["foo"]] and set with X[[1]][["foo"]] = bar. It is not like you have a fixed set of allowed keys in the association; fields can be created and deleted (KeyDrop) dynamically. But I guess that's what comes closed to what you ask for.
$endgroup$
– Henrik Schumacher
Apr 12 at 11:38






$begingroup$
@JyrkiLahtonen Indeed, I would suggest to use Association wrapped by a head to indicate the "class". So an instance of the class would look like X = JyrkisRubikCube[Association[...]]. Then you can use TagSetDelayed for defining and overloading methods for this class. A field/property "foo" of X can then accessed with X[[1]][["foo"]] and set with X[[1]][["foo"]] = bar. It is not like you have a fixed set of allowed keys in the association; fields can be created and deleted (KeyDrop) dynamically. But I guess that's what comes closed to what you ask for.
$endgroup$
– Henrik Schumacher
Apr 12 at 11:38














$begingroup$
@Szabolcs Visualization is exactly the goal here. I plan to use this to make a few concepts from a first course on groups more concrete to a bunch of people at freshman level. I won't be ignoring the algebra, because I teach algebra for living. Of course, this is also just for fun.
$endgroup$
– Jyrki Lahtonen
Apr 12 at 11:38




$begingroup$
@Szabolcs Visualization is exactly the goal here. I plan to use this to make a few concepts from a first course on groups more concrete to a bunch of people at freshman level. I won't be ignoring the algebra, because I teach algebra for living. Of course, this is also just for fun.
$endgroup$
– Jyrki Lahtonen
Apr 12 at 11:38










1 Answer
1






active

oldest

votes


















10












$begingroup$

Update 2



Per request, I extended this to handle arbitrary sizes and rotations. It was a huge hassle to figure out how to get the appropriate permutations for the individual rotations for arbitrary sized cubes, but it worked out. Here's what it looks like:



r1 = RubiksCube["Size" -> 4];

r1@"Colors" = ColorData["Atoms"] /@ {6, 7, 8, 9, 11, 13, 18};
r1@"Show"[Method -> {"ShrinkWrap" -> True}]


enter image description here



And we can visualize these with different kinds of rotations and different origins:



r2 = RubiksCube["Origin" -> {10, 0, 0}, "Size" -> 10];

Show[
r1@"Twist"[.5, {"Y", 2}]@"Twist"[.5, {"Y", 4}]@"Show",
r2@"Show",
PlotRange -> All
]


enter image description here



Fullish Imp



I took Roman Maeder's Rubiks Cube Demo and recast it in an OOP manner using the package I talk about below.



I put this on GitHub here so people can check it out.



You'll need the InterfaceObjects package to make this work, but once you have it you can try it out like:



Get["https://github.com/b3m2a1/mathematica-tools/raw/master/RubiksCube.wl"]

new = RubiksCube


enter image description here



Then use it like:



new@"Show"


enter image description here



Or:



Manipulate[
Fold[
#@"Twist"[#2[[1]], #2[[2]]] &,
new,
Thread[
{
{b, f, l, r, d, u},
{"Back", "Front", "Left", "Right", "Down", "Up"}
}
]
]@"Show",
{b, 0, 2 π, .01},
{f, 0, 2 π, .01},
{l, 0, 2 π, .01},
{r, 0, 2 π, .01},
{d, 0, 2 π, .01},
{u, 0, 2 π, .01},
DisplayAllSteps -> True
]


enter image description here



And just to see how deep the OOP runs, each cube inside that thing is its own object:



new["Cuboids"][[1, 1, 1]]


enter image description here



Finally, maybe you prefer a different colored cube:



new@"Colors" = ColorData[97] /@ Range[7]


enter image description here



This is what OOP makes easy for you



Original



It sounds as if you're really trying to do OOP in Mathematica. Honestly, the language isn't great for that, but there are things like SparseArray and friends that support some OOP and methods and stuff. So I wrote a package to automate that. Maybe it'll be useful. You can get it from here.



To use it we "register" a new object:



<< InterfaceObjects`

RegisterInterface[
RubiksCube,
{
"Size",
"VertexList"
},
"Constructor" -> constructRubiksCube,
"MutationFunctions" -> {"Keys", "Parts"}
]

RubiksCube


This tells us that we have a new type with required attributes "Size" and "VertexList" and which uses constructRubiksCube as its base constructor. It can be mutated on either its "Keys" or "Parts".



Next we define some functions to act on the data stored in this object as well as our constructor:



constructRubiksCube[size : _?NumberQ : .1, 
vertextList : _List | Automatic : Automatic] :=
<|

"Size" -> size,
"VertexList" ->
Replace[vertextList, Automatic -> RandomReal[{}, {9, 3}]]
|>;
newVertices[r_RubiksCube] :=

InterfaceModify[RubiksCube, (*
this is here just for type safety stuff *)
r,
Function[{properties},
ReplacePart[properties,
"VertexList" -> RandomReal[{}, {9, 3}]
]
]
];
displayCube[r_RubiksCube] :=

With[{v = r["VertexList"], s = r["Size"]},
Graphics3D[
Map[Scale[Cuboid[#], s] &, v]
]
];


That InterfaceModify function basically just allows you to change the state of the object. Keep in mind that it returns a new object since Mathematica doesn't do OOP for real.



Then we attach these as methods to our object:



InterfaceMethod[RubiksCube]@
r_RubiksCube["Show"] := displayCube[r];
InterfaceMethod[RubiksCube]@
r_RubiksCube["NewVertices"] := newVertices[r];


And now we can make a cube:



r = RubiksCube;



Query props:



r@"Size"

0.1

r@"VertexList"

{{0.471592, 0.554128, 0.669796}, {0.360993, 0.228342,
0.337433}, {0.0738407, 0.522903, 0.0469278}, {0.992347, 0.84807,
0.83663}, {0.451908, 0.667543, 0.01672}, {0.181584, 0.660202,
0.100972}, {0.857532, 0.474982, 0.684844}, {0.905125, 0.127964,
0.81153}, {0.654156, 0.0892593, 0.493546}}


Discover properties / methods:



r@"Methods"

{"Show", "NewVertices"}

r@"Properties"

{"Size", "VertexList", "Version", "Properties", "Methods"}


Call our methods:



r@"Show"


enter image description here



r@"NewVertices"@"Show"


enter image description here



And modify things:



r@"Size" = 2;

r@"Show"


enter image description here



Dunno if this will be useful for you but I use it in lots of my packages to define outward facing interfaces.






share|improve this answer











$endgroup$













  • $begingroup$
    I appreciate the effort you put into this. However, I don't grok OOP AT ALL, so I cannot build my demos on top of this. Obviously I can learn a lot from studying Roman's and your code, but before I get there I would need to learn something else first.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 21:59










  • $begingroup$
    If I use your code can I then have two different size Rubik cube's in visible at the same time.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 22:01








  • 1




    $begingroup$
    @JyrkiLahtonen give OOP a try. You were basically asking about how to do OOP in your question. Your Pascal "record" is just an object. A C struct is just an object but with fewer features.
    $endgroup$
    – b3m2a1
    Apr 12 at 22:01












  • $begingroup$
    Also, you didn't seem to do anything with the variable size, As in size=3 produces a 3x3x3 cube, size=4 a 4x4x4 cube etc.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 22:02






  • 1




    $begingroup$
    @JyrkiLahtonen Mathematica doesn't actually support OOP. I made it emulate OOP because OOP is the cleanest way I've found to think about programming. "Use the same snippet of code on several objects" == define a method for an object.
    $endgroup$
    – b3m2a1
    Apr 12 at 22:11












Your Answer








StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "387"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f195064%2fpascal-records-and-mathematica-programming%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









10












$begingroup$

Update 2



Per request, I extended this to handle arbitrary sizes and rotations. It was a huge hassle to figure out how to get the appropriate permutations for the individual rotations for arbitrary sized cubes, but it worked out. Here's what it looks like:



r1 = RubiksCube["Size" -> 4];

r1@"Colors" = ColorData["Atoms"] /@ {6, 7, 8, 9, 11, 13, 18};
r1@"Show"[Method -> {"ShrinkWrap" -> True}]


enter image description here



And we can visualize these with different kinds of rotations and different origins:



r2 = RubiksCube["Origin" -> {10, 0, 0}, "Size" -> 10];

Show[
r1@"Twist"[.5, {"Y", 2}]@"Twist"[.5, {"Y", 4}]@"Show",
r2@"Show",
PlotRange -> All
]


enter image description here



Fullish Imp



I took Roman Maeder's Rubiks Cube Demo and recast it in an OOP manner using the package I talk about below.



I put this on GitHub here so people can check it out.



You'll need the InterfaceObjects package to make this work, but once you have it you can try it out like:



Get["https://github.com/b3m2a1/mathematica-tools/raw/master/RubiksCube.wl"]

new = RubiksCube


enter image description here



Then use it like:



new@"Show"


enter image description here



Or:



Manipulate[
Fold[
#@"Twist"[#2[[1]], #2[[2]]] &,
new,
Thread[
{
{b, f, l, r, d, u},
{"Back", "Front", "Left", "Right", "Down", "Up"}
}
]
]@"Show",
{b, 0, 2 π, .01},
{f, 0, 2 π, .01},
{l, 0, 2 π, .01},
{r, 0, 2 π, .01},
{d, 0, 2 π, .01},
{u, 0, 2 π, .01},
DisplayAllSteps -> True
]


enter image description here



And just to see how deep the OOP runs, each cube inside that thing is its own object:



new["Cuboids"][[1, 1, 1]]


enter image description here



Finally, maybe you prefer a different colored cube:



new@"Colors" = ColorData[97] /@ Range[7]


enter image description here



This is what OOP makes easy for you



Original



It sounds as if you're really trying to do OOP in Mathematica. Honestly, the language isn't great for that, but there are things like SparseArray and friends that support some OOP and methods and stuff. So I wrote a package to automate that. Maybe it'll be useful. You can get it from here.



To use it we "register" a new object:



<< InterfaceObjects`

RegisterInterface[
RubiksCube,
{
"Size",
"VertexList"
},
"Constructor" -> constructRubiksCube,
"MutationFunctions" -> {"Keys", "Parts"}
]

RubiksCube


This tells us that we have a new type with required attributes "Size" and "VertexList" and which uses constructRubiksCube as its base constructor. It can be mutated on either its "Keys" or "Parts".



Next we define some functions to act on the data stored in this object as well as our constructor:



constructRubiksCube[size : _?NumberQ : .1, 
vertextList : _List | Automatic : Automatic] :=
<|

"Size" -> size,
"VertexList" ->
Replace[vertextList, Automatic -> RandomReal[{}, {9, 3}]]
|>;
newVertices[r_RubiksCube] :=

InterfaceModify[RubiksCube, (*
this is here just for type safety stuff *)
r,
Function[{properties},
ReplacePart[properties,
"VertexList" -> RandomReal[{}, {9, 3}]
]
]
];
displayCube[r_RubiksCube] :=

With[{v = r["VertexList"], s = r["Size"]},
Graphics3D[
Map[Scale[Cuboid[#], s] &, v]
]
];


That InterfaceModify function basically just allows you to change the state of the object. Keep in mind that it returns a new object since Mathematica doesn't do OOP for real.



Then we attach these as methods to our object:



InterfaceMethod[RubiksCube]@
r_RubiksCube["Show"] := displayCube[r];
InterfaceMethod[RubiksCube]@
r_RubiksCube["NewVertices"] := newVertices[r];


And now we can make a cube:



r = RubiksCube;



Query props:



r@"Size"

0.1

r@"VertexList"

{{0.471592, 0.554128, 0.669796}, {0.360993, 0.228342,
0.337433}, {0.0738407, 0.522903, 0.0469278}, {0.992347, 0.84807,
0.83663}, {0.451908, 0.667543, 0.01672}, {0.181584, 0.660202,
0.100972}, {0.857532, 0.474982, 0.684844}, {0.905125, 0.127964,
0.81153}, {0.654156, 0.0892593, 0.493546}}


Discover properties / methods:



r@"Methods"

{"Show", "NewVertices"}

r@"Properties"

{"Size", "VertexList", "Version", "Properties", "Methods"}


Call our methods:



r@"Show"


enter image description here



r@"NewVertices"@"Show"


enter image description here



And modify things:



r@"Size" = 2;

r@"Show"


enter image description here



Dunno if this will be useful for you but I use it in lots of my packages to define outward facing interfaces.






share|improve this answer











$endgroup$













  • $begingroup$
    I appreciate the effort you put into this. However, I don't grok OOP AT ALL, so I cannot build my demos on top of this. Obviously I can learn a lot from studying Roman's and your code, but before I get there I would need to learn something else first.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 21:59










  • $begingroup$
    If I use your code can I then have two different size Rubik cube's in visible at the same time.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 22:01








  • 1




    $begingroup$
    @JyrkiLahtonen give OOP a try. You were basically asking about how to do OOP in your question. Your Pascal "record" is just an object. A C struct is just an object but with fewer features.
    $endgroup$
    – b3m2a1
    Apr 12 at 22:01












  • $begingroup$
    Also, you didn't seem to do anything with the variable size, As in size=3 produces a 3x3x3 cube, size=4 a 4x4x4 cube etc.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 22:02






  • 1




    $begingroup$
    @JyrkiLahtonen Mathematica doesn't actually support OOP. I made it emulate OOP because OOP is the cleanest way I've found to think about programming. "Use the same snippet of code on several objects" == define a method for an object.
    $endgroup$
    – b3m2a1
    Apr 12 at 22:11
















10












$begingroup$

Update 2



Per request, I extended this to handle arbitrary sizes and rotations. It was a huge hassle to figure out how to get the appropriate permutations for the individual rotations for arbitrary sized cubes, but it worked out. Here's what it looks like:



r1 = RubiksCube["Size" -> 4];

r1@"Colors" = ColorData["Atoms"] /@ {6, 7, 8, 9, 11, 13, 18};
r1@"Show"[Method -> {"ShrinkWrap" -> True}]


enter image description here



And we can visualize these with different kinds of rotations and different origins:



r2 = RubiksCube["Origin" -> {10, 0, 0}, "Size" -> 10];

Show[
r1@"Twist"[.5, {"Y", 2}]@"Twist"[.5, {"Y", 4}]@"Show",
r2@"Show",
PlotRange -> All
]


enter image description here



Fullish Imp



I took Roman Maeder's Rubiks Cube Demo and recast it in an OOP manner using the package I talk about below.



I put this on GitHub here so people can check it out.



You'll need the InterfaceObjects package to make this work, but once you have it you can try it out like:



Get["https://github.com/b3m2a1/mathematica-tools/raw/master/RubiksCube.wl"]

new = RubiksCube


enter image description here



Then use it like:



new@"Show"


enter image description here



Or:



Manipulate[
Fold[
#@"Twist"[#2[[1]], #2[[2]]] &,
new,
Thread[
{
{b, f, l, r, d, u},
{"Back", "Front", "Left", "Right", "Down", "Up"}
}
]
]@"Show",
{b, 0, 2 π, .01},
{f, 0, 2 π, .01},
{l, 0, 2 π, .01},
{r, 0, 2 π, .01},
{d, 0, 2 π, .01},
{u, 0, 2 π, .01},
DisplayAllSteps -> True
]


enter image description here



And just to see how deep the OOP runs, each cube inside that thing is its own object:



new["Cuboids"][[1, 1, 1]]


enter image description here



Finally, maybe you prefer a different colored cube:



new@"Colors" = ColorData[97] /@ Range[7]


enter image description here



This is what OOP makes easy for you



Original



It sounds as if you're really trying to do OOP in Mathematica. Honestly, the language isn't great for that, but there are things like SparseArray and friends that support some OOP and methods and stuff. So I wrote a package to automate that. Maybe it'll be useful. You can get it from here.



To use it we "register" a new object:



<< InterfaceObjects`

RegisterInterface[
RubiksCube,
{
"Size",
"VertexList"
},
"Constructor" -> constructRubiksCube,
"MutationFunctions" -> {"Keys", "Parts"}
]

RubiksCube


This tells us that we have a new type with required attributes "Size" and "VertexList" and which uses constructRubiksCube as its base constructor. It can be mutated on either its "Keys" or "Parts".



Next we define some functions to act on the data stored in this object as well as our constructor:



constructRubiksCube[size : _?NumberQ : .1, 
vertextList : _List | Automatic : Automatic] :=
<|

"Size" -> size,
"VertexList" ->
Replace[vertextList, Automatic -> RandomReal[{}, {9, 3}]]
|>;
newVertices[r_RubiksCube] :=

InterfaceModify[RubiksCube, (*
this is here just for type safety stuff *)
r,
Function[{properties},
ReplacePart[properties,
"VertexList" -> RandomReal[{}, {9, 3}]
]
]
];
displayCube[r_RubiksCube] :=

With[{v = r["VertexList"], s = r["Size"]},
Graphics3D[
Map[Scale[Cuboid[#], s] &, v]
]
];


That InterfaceModify function basically just allows you to change the state of the object. Keep in mind that it returns a new object since Mathematica doesn't do OOP for real.



Then we attach these as methods to our object:



InterfaceMethod[RubiksCube]@
r_RubiksCube["Show"] := displayCube[r];
InterfaceMethod[RubiksCube]@
r_RubiksCube["NewVertices"] := newVertices[r];


And now we can make a cube:



r = RubiksCube;



Query props:



r@"Size"

0.1

r@"VertexList"

{{0.471592, 0.554128, 0.669796}, {0.360993, 0.228342,
0.337433}, {0.0738407, 0.522903, 0.0469278}, {0.992347, 0.84807,
0.83663}, {0.451908, 0.667543, 0.01672}, {0.181584, 0.660202,
0.100972}, {0.857532, 0.474982, 0.684844}, {0.905125, 0.127964,
0.81153}, {0.654156, 0.0892593, 0.493546}}


Discover properties / methods:



r@"Methods"

{"Show", "NewVertices"}

r@"Properties"

{"Size", "VertexList", "Version", "Properties", "Methods"}


Call our methods:



r@"Show"


enter image description here



r@"NewVertices"@"Show"


enter image description here



And modify things:



r@"Size" = 2;

r@"Show"


enter image description here



Dunno if this will be useful for you but I use it in lots of my packages to define outward facing interfaces.






share|improve this answer











$endgroup$













  • $begingroup$
    I appreciate the effort you put into this. However, I don't grok OOP AT ALL, so I cannot build my demos on top of this. Obviously I can learn a lot from studying Roman's and your code, but before I get there I would need to learn something else first.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 21:59










  • $begingroup$
    If I use your code can I then have two different size Rubik cube's in visible at the same time.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 22:01








  • 1




    $begingroup$
    @JyrkiLahtonen give OOP a try. You were basically asking about how to do OOP in your question. Your Pascal "record" is just an object. A C struct is just an object but with fewer features.
    $endgroup$
    – b3m2a1
    Apr 12 at 22:01












  • $begingroup$
    Also, you didn't seem to do anything with the variable size, As in size=3 produces a 3x3x3 cube, size=4 a 4x4x4 cube etc.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 22:02






  • 1




    $begingroup$
    @JyrkiLahtonen Mathematica doesn't actually support OOP. I made it emulate OOP because OOP is the cleanest way I've found to think about programming. "Use the same snippet of code on several objects" == define a method for an object.
    $endgroup$
    – b3m2a1
    Apr 12 at 22:11














10












10








10





$begingroup$

Update 2



Per request, I extended this to handle arbitrary sizes and rotations. It was a huge hassle to figure out how to get the appropriate permutations for the individual rotations for arbitrary sized cubes, but it worked out. Here's what it looks like:



r1 = RubiksCube["Size" -> 4];

r1@"Colors" = ColorData["Atoms"] /@ {6, 7, 8, 9, 11, 13, 18};
r1@"Show"[Method -> {"ShrinkWrap" -> True}]


enter image description here



And we can visualize these with different kinds of rotations and different origins:



r2 = RubiksCube["Origin" -> {10, 0, 0}, "Size" -> 10];

Show[
r1@"Twist"[.5, {"Y", 2}]@"Twist"[.5, {"Y", 4}]@"Show",
r2@"Show",
PlotRange -> All
]


enter image description here



Fullish Imp



I took Roman Maeder's Rubiks Cube Demo and recast it in an OOP manner using the package I talk about below.



I put this on GitHub here so people can check it out.



You'll need the InterfaceObjects package to make this work, but once you have it you can try it out like:



Get["https://github.com/b3m2a1/mathematica-tools/raw/master/RubiksCube.wl"]

new = RubiksCube


enter image description here



Then use it like:



new@"Show"


enter image description here



Or:



Manipulate[
Fold[
#@"Twist"[#2[[1]], #2[[2]]] &,
new,
Thread[
{
{b, f, l, r, d, u},
{"Back", "Front", "Left", "Right", "Down", "Up"}
}
]
]@"Show",
{b, 0, 2 π, .01},
{f, 0, 2 π, .01},
{l, 0, 2 π, .01},
{r, 0, 2 π, .01},
{d, 0, 2 π, .01},
{u, 0, 2 π, .01},
DisplayAllSteps -> True
]


enter image description here



And just to see how deep the OOP runs, each cube inside that thing is its own object:



new["Cuboids"][[1, 1, 1]]


enter image description here



Finally, maybe you prefer a different colored cube:



new@"Colors" = ColorData[97] /@ Range[7]


enter image description here



This is what OOP makes easy for you



Original



It sounds as if you're really trying to do OOP in Mathematica. Honestly, the language isn't great for that, but there are things like SparseArray and friends that support some OOP and methods and stuff. So I wrote a package to automate that. Maybe it'll be useful. You can get it from here.



To use it we "register" a new object:



<< InterfaceObjects`

RegisterInterface[
RubiksCube,
{
"Size",
"VertexList"
},
"Constructor" -> constructRubiksCube,
"MutationFunctions" -> {"Keys", "Parts"}
]

RubiksCube


This tells us that we have a new type with required attributes "Size" and "VertexList" and which uses constructRubiksCube as its base constructor. It can be mutated on either its "Keys" or "Parts".



Next we define some functions to act on the data stored in this object as well as our constructor:



constructRubiksCube[size : _?NumberQ : .1, 
vertextList : _List | Automatic : Automatic] :=
<|

"Size" -> size,
"VertexList" ->
Replace[vertextList, Automatic -> RandomReal[{}, {9, 3}]]
|>;
newVertices[r_RubiksCube] :=

InterfaceModify[RubiksCube, (*
this is here just for type safety stuff *)
r,
Function[{properties},
ReplacePart[properties,
"VertexList" -> RandomReal[{}, {9, 3}]
]
]
];
displayCube[r_RubiksCube] :=

With[{v = r["VertexList"], s = r["Size"]},
Graphics3D[
Map[Scale[Cuboid[#], s] &, v]
]
];


That InterfaceModify function basically just allows you to change the state of the object. Keep in mind that it returns a new object since Mathematica doesn't do OOP for real.



Then we attach these as methods to our object:



InterfaceMethod[RubiksCube]@
r_RubiksCube["Show"] := displayCube[r];
InterfaceMethod[RubiksCube]@
r_RubiksCube["NewVertices"] := newVertices[r];


And now we can make a cube:



r = RubiksCube;



Query props:



r@"Size"

0.1

r@"VertexList"

{{0.471592, 0.554128, 0.669796}, {0.360993, 0.228342,
0.337433}, {0.0738407, 0.522903, 0.0469278}, {0.992347, 0.84807,
0.83663}, {0.451908, 0.667543, 0.01672}, {0.181584, 0.660202,
0.100972}, {0.857532, 0.474982, 0.684844}, {0.905125, 0.127964,
0.81153}, {0.654156, 0.0892593, 0.493546}}


Discover properties / methods:



r@"Methods"

{"Show", "NewVertices"}

r@"Properties"

{"Size", "VertexList", "Version", "Properties", "Methods"}


Call our methods:



r@"Show"


enter image description here



r@"NewVertices"@"Show"


enter image description here



And modify things:



r@"Size" = 2;

r@"Show"


enter image description here



Dunno if this will be useful for you but I use it in lots of my packages to define outward facing interfaces.






share|improve this answer











$endgroup$



Update 2



Per request, I extended this to handle arbitrary sizes and rotations. It was a huge hassle to figure out how to get the appropriate permutations for the individual rotations for arbitrary sized cubes, but it worked out. Here's what it looks like:



r1 = RubiksCube["Size" -> 4];

r1@"Colors" = ColorData["Atoms"] /@ {6, 7, 8, 9, 11, 13, 18};
r1@"Show"[Method -> {"ShrinkWrap" -> True}]


enter image description here



And we can visualize these with different kinds of rotations and different origins:



r2 = RubiksCube["Origin" -> {10, 0, 0}, "Size" -> 10];

Show[
r1@"Twist"[.5, {"Y", 2}]@"Twist"[.5, {"Y", 4}]@"Show",
r2@"Show",
PlotRange -> All
]


enter image description here



Fullish Imp



I took Roman Maeder's Rubiks Cube Demo and recast it in an OOP manner using the package I talk about below.



I put this on GitHub here so people can check it out.



You'll need the InterfaceObjects package to make this work, but once you have it you can try it out like:



Get["https://github.com/b3m2a1/mathematica-tools/raw/master/RubiksCube.wl"]

new = RubiksCube


enter image description here



Then use it like:



new@"Show"


enter image description here



Or:



Manipulate[
Fold[
#@"Twist"[#2[[1]], #2[[2]]] &,
new,
Thread[
{
{b, f, l, r, d, u},
{"Back", "Front", "Left", "Right", "Down", "Up"}
}
]
]@"Show",
{b, 0, 2 π, .01},
{f, 0, 2 π, .01},
{l, 0, 2 π, .01},
{r, 0, 2 π, .01},
{d, 0, 2 π, .01},
{u, 0, 2 π, .01},
DisplayAllSteps -> True
]


enter image description here



And just to see how deep the OOP runs, each cube inside that thing is its own object:



new["Cuboids"][[1, 1, 1]]


enter image description here



Finally, maybe you prefer a different colored cube:



new@"Colors" = ColorData[97] /@ Range[7]


enter image description here



This is what OOP makes easy for you



Original



It sounds as if you're really trying to do OOP in Mathematica. Honestly, the language isn't great for that, but there are things like SparseArray and friends that support some OOP and methods and stuff. So I wrote a package to automate that. Maybe it'll be useful. You can get it from here.



To use it we "register" a new object:



<< InterfaceObjects`

RegisterInterface[
RubiksCube,
{
"Size",
"VertexList"
},
"Constructor" -> constructRubiksCube,
"MutationFunctions" -> {"Keys", "Parts"}
]

RubiksCube


This tells us that we have a new type with required attributes "Size" and "VertexList" and which uses constructRubiksCube as its base constructor. It can be mutated on either its "Keys" or "Parts".



Next we define some functions to act on the data stored in this object as well as our constructor:



constructRubiksCube[size : _?NumberQ : .1, 
vertextList : _List | Automatic : Automatic] :=
<|

"Size" -> size,
"VertexList" ->
Replace[vertextList, Automatic -> RandomReal[{}, {9, 3}]]
|>;
newVertices[r_RubiksCube] :=

InterfaceModify[RubiksCube, (*
this is here just for type safety stuff *)
r,
Function[{properties},
ReplacePart[properties,
"VertexList" -> RandomReal[{}, {9, 3}]
]
]
];
displayCube[r_RubiksCube] :=

With[{v = r["VertexList"], s = r["Size"]},
Graphics3D[
Map[Scale[Cuboid[#], s] &, v]
]
];


That InterfaceModify function basically just allows you to change the state of the object. Keep in mind that it returns a new object since Mathematica doesn't do OOP for real.



Then we attach these as methods to our object:



InterfaceMethod[RubiksCube]@
r_RubiksCube["Show"] := displayCube[r];
InterfaceMethod[RubiksCube]@
r_RubiksCube["NewVertices"] := newVertices[r];


And now we can make a cube:



r = RubiksCube;



Query props:



r@"Size"

0.1

r@"VertexList"

{{0.471592, 0.554128, 0.669796}, {0.360993, 0.228342,
0.337433}, {0.0738407, 0.522903, 0.0469278}, {0.992347, 0.84807,
0.83663}, {0.451908, 0.667543, 0.01672}, {0.181584, 0.660202,
0.100972}, {0.857532, 0.474982, 0.684844}, {0.905125, 0.127964,
0.81153}, {0.654156, 0.0892593, 0.493546}}


Discover properties / methods:



r@"Methods"

{"Show", "NewVertices"}

r@"Properties"

{"Size", "VertexList", "Version", "Properties", "Methods"}


Call our methods:



r@"Show"


enter image description here



r@"NewVertices"@"Show"


enter image description here



And modify things:



r@"Size" = 2;

r@"Show"


enter image description here



Dunno if this will be useful for you but I use it in lots of my packages to define outward facing interfaces.







share|improve this answer














share|improve this answer



share|improve this answer








edited Apr 13 at 0:25

























answered Apr 12 at 11:43









b3m2a1b3m2a1

28.9k360167




28.9k360167












  • $begingroup$
    I appreciate the effort you put into this. However, I don't grok OOP AT ALL, so I cannot build my demos on top of this. Obviously I can learn a lot from studying Roman's and your code, but before I get there I would need to learn something else first.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 21:59










  • $begingroup$
    If I use your code can I then have two different size Rubik cube's in visible at the same time.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 22:01








  • 1




    $begingroup$
    @JyrkiLahtonen give OOP a try. You were basically asking about how to do OOP in your question. Your Pascal "record" is just an object. A C struct is just an object but with fewer features.
    $endgroup$
    – b3m2a1
    Apr 12 at 22:01












  • $begingroup$
    Also, you didn't seem to do anything with the variable size, As in size=3 produces a 3x3x3 cube, size=4 a 4x4x4 cube etc.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 22:02






  • 1




    $begingroup$
    @JyrkiLahtonen Mathematica doesn't actually support OOP. I made it emulate OOP because OOP is the cleanest way I've found to think about programming. "Use the same snippet of code on several objects" == define a method for an object.
    $endgroup$
    – b3m2a1
    Apr 12 at 22:11


















  • $begingroup$
    I appreciate the effort you put into this. However, I don't grok OOP AT ALL, so I cannot build my demos on top of this. Obviously I can learn a lot from studying Roman's and your code, but before I get there I would need to learn something else first.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 21:59










  • $begingroup$
    If I use your code can I then have two different size Rubik cube's in visible at the same time.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 22:01








  • 1




    $begingroup$
    @JyrkiLahtonen give OOP a try. You were basically asking about how to do OOP in your question. Your Pascal "record" is just an object. A C struct is just an object but with fewer features.
    $endgroup$
    – b3m2a1
    Apr 12 at 22:01












  • $begingroup$
    Also, you didn't seem to do anything with the variable size, As in size=3 produces a 3x3x3 cube, size=4 a 4x4x4 cube etc.
    $endgroup$
    – Jyrki Lahtonen
    Apr 12 at 22:02






  • 1




    $begingroup$
    @JyrkiLahtonen Mathematica doesn't actually support OOP. I made it emulate OOP because OOP is the cleanest way I've found to think about programming. "Use the same snippet of code on several objects" == define a method for an object.
    $endgroup$
    – b3m2a1
    Apr 12 at 22:11
















$begingroup$
I appreciate the effort you put into this. However, I don't grok OOP AT ALL, so I cannot build my demos on top of this. Obviously I can learn a lot from studying Roman's and your code, but before I get there I would need to learn something else first.
$endgroup$
– Jyrki Lahtonen
Apr 12 at 21:59




$begingroup$
I appreciate the effort you put into this. However, I don't grok OOP AT ALL, so I cannot build my demos on top of this. Obviously I can learn a lot from studying Roman's and your code, but before I get there I would need to learn something else first.
$endgroup$
– Jyrki Lahtonen
Apr 12 at 21:59












$begingroup$
If I use your code can I then have two different size Rubik cube's in visible at the same time.
$endgroup$
– Jyrki Lahtonen
Apr 12 at 22:01






$begingroup$
If I use your code can I then have two different size Rubik cube's in visible at the same time.
$endgroup$
– Jyrki Lahtonen
Apr 12 at 22:01






1




1




$begingroup$
@JyrkiLahtonen give OOP a try. You were basically asking about how to do OOP in your question. Your Pascal "record" is just an object. A C struct is just an object but with fewer features.
$endgroup$
– b3m2a1
Apr 12 at 22:01






$begingroup$
@JyrkiLahtonen give OOP a try. You were basically asking about how to do OOP in your question. Your Pascal "record" is just an object. A C struct is just an object but with fewer features.
$endgroup$
– b3m2a1
Apr 12 at 22:01














$begingroup$
Also, you didn't seem to do anything with the variable size, As in size=3 produces a 3x3x3 cube, size=4 a 4x4x4 cube etc.
$endgroup$
– Jyrki Lahtonen
Apr 12 at 22:02




$begingroup$
Also, you didn't seem to do anything with the variable size, As in size=3 produces a 3x3x3 cube, size=4 a 4x4x4 cube etc.
$endgroup$
– Jyrki Lahtonen
Apr 12 at 22:02




1




1




$begingroup$
@JyrkiLahtonen Mathematica doesn't actually support OOP. I made it emulate OOP because OOP is the cleanest way I've found to think about programming. "Use the same snippet of code on several objects" == define a method for an object.
$endgroup$
– b3m2a1
Apr 12 at 22:11




$begingroup$
@JyrkiLahtonen Mathematica doesn't actually support OOP. I made it emulate OOP because OOP is the cleanest way I've found to think about programming. "Use the same snippet of code on several objects" == define a method for an object.
$endgroup$
– b3m2a1
Apr 12 at 22:11


















draft saved

draft discarded




















































Thanks for contributing an answer to Mathematica Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f195064%2fpascal-records-and-mathematica-programming%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Plaza Victoria

Puebla de Zaragoza

Musa