588
587
return (pos / w->cubes.sizeRect);
592
Cartesian(CubesWidget w, int pos, int * x, int * y)
591
CartesianX(CubesWidget w, int pos)
594
*x = Column(w, pos) * w->cubes.offset.x + w->cubes.delta.x +
595
x = Column(w, pos) * w->cubes.offset.x + w->cubes.delta.x +
595
596
w->cubes.puzzleOffset.x;
596
*y = Row(w, pos) * w->cubes.offset.y + w->cubes.delta.y +
597
if (!w->cubes.vertical) {
598
x += Stack(w, pos) * (w->cubes.sizeX * w->cubes.offset.x + 1);
604
CartesianY(CubesWidget w, int pos)
608
y = Row(w, pos) * w->cubes.offset.y + w->cubes.delta.y +
597
609
w->cubes.puzzleOffset.y;
598
610
if (w->cubes.vertical) {
599
*y += Stack(w, pos) * (w->cubes.sizeY * w->cubes.offset.y + 1);
601
*x += Stack(w, pos) * (w->cubes.sizeX * w->cubes.offset.x + 1);
611
y += Stack(w, pos) * (w->cubes.sizeY * w->cubes.offset.y + 1);
737
748
w->cubes.sizeBlock;
740
Cartesian(w, pos, &dx, &dy);
741
dx += offsetX + pressedOffset;
742
dy += offsetY + pressedOffset;
743
Cartesian(w, block, &sx, &sy);
751
dx = CartesianX(w, pos) + offsetX + pressedOffset;
752
dy = CartesianY(w, pos) + offsetY + pressedOffset;
753
sx = CartesianX(w, block);
754
sy = CartesianY(w, block);
745
756
FILLRECTANGLE(w, dr,
746
757
(erase) ? w->cubes.inverseGC : w->cubes.blockGC,
780
791
w->cubes.sizeBlock;
783
Cartesian(w, pos, &dx, &dy);
784
dx += offsetX + pressedOffset;
785
dy += offsetY + pressedOffset;
786
Cartesian(w, block, &sx, &sy);
794
dx = CartesianX(w, pos) + offsetX + pressedOffset;
795
dy = CartesianY(w, pos) + offsetY + pressedOffset;
796
sx = CartesianX(w, block);
797
sy = CartesianY(w, block);
788
799
FILLRECTANGLE(w, dr,
789
800
(erase) ? w->cubes.inverseGC : w->cubes.blockGC,
905
914
fillBeginPos = BlockNFromSpace(w, numBlocks, dir);
906
915
if ((dir == RIGHT) || (dir == LEFT)) {
907
Cartesian(w, fillBeginPos, &fillBeginI, &dy);
916
fillBeginI = CartesianX(w, fillBeginPos);
908
917
gapI = w->cubes.blockSize.x * fast / w->cubes.numSlices;
909
918
moveI = w->cubes.blockSize.x + w->cubes.delta.x;
910
919
} else if ((dir == TOP) || (dir == BOTTOM)) {
911
Cartesian(w, fillBeginPos, &dx, &fillBeginI);
920
fillBeginI = CartesianY(w, fillBeginPos);
912
921
gapI = w->cubes.blockSize.y * fast / w->cubes.numSlices;
913
922
moveI = w->cubes.blockSize.y + w->cubes.delta.y;
942
952
if (aBlock < numBlocks - 1) {
947
ix, iy + w->cubes.blockSize.y,
948
w->cubes.blockSize.x, gapI);
953
ix - gapI, iy, gapI, w->cubes.blockSize.y);
958
ix, iy - gapI, w->cubes.blockSize.x, gapI);
963
ix + w->cubes.blockSize.x, iy,
964
gapI, w->cubes.blockSize.y);
957
ix, iy + w->cubes.blockSize.y,
958
w->cubes.blockSize.x, gapI);
964
iy, gapI, w->cubes.blockSize.y);
970
w->cubes.blockSize.x, gapI);
975
ix + w->cubes.blockSize.x, iy,
976
gapI, w->cubes.blockSize.y);
972
ix, iy + w->cubes.blockSize.y,
973
w->cubes.blockSize.x, fillBeginI - iy);
979
ix - fillBeginI, w->cubes.blockSize.y);
985
w->cubes.blockSize.x, iy - fillBeginI);
990
ix + w->cubes.blockSize.x, iy,
991
fillBeginI - ix, w->cubes.blockSize.y);
984
ix, iy + w->cubes.blockSize.y,
985
w->cubes.blockSize.x, fillBeginI - iy);
991
ix - fillBeginI, w->cubes.blockSize.y);
997
w->cubes.blockSize.x, iy - fillBeginI);
1000
FILLRECTANGLE(w, dr,
1002
ix + w->cubes.blockSize.x, iy,
1003
fillBeginI - ix, w->cubes.blockSize.y);
1010
1022
AnimateMove(CubesWidget w, int fromPos, int fast)
1012
1024
int pos = w->cubes.spacePosition;
1013
int dx, dy, fromdx, fromdy;
1014
1026
int xToCenter, yToCenter;
1015
1027
int incTo, incAt, inc;
1018
Cartesian(w, pos, &dx, &dy);
1019
Cartesian(w, fromPos, &fromdx, &fromdy);
1030
dx = CartesianX(w, pos);
1031
dy = CartesianY(w, pos);
1032
fx = CartesianX(w, fromPos);
1033
fy = CartesianY(w, fromPos);
1020
1034
xToCenter = w->cubes.blockSize.x / 2;
1021
1035
yToCenter = w->cubes.blockSize.y / 2;
1022
1036
incTo = MIN(w->cubes.blockSize.x, w->cubes.blockSize.y) / 2;
1025
1039
FILLRECTANGLE(w, dr,
1026
1040
w->cubes.inverseGC,
1027
fromdx, fromdy, incAt, w->cubes.blockSize.y);
1028
FILLRECTANGLE(w, dr,
1030
fromdx, fromdy, w->cubes.blockSize.x, incAt);
1031
FILLRECTANGLE(w, dr,
1033
fromdx + w->cubes.blockSize.x - incAt, fromdy,
1041
fx, fy, incAt, w->cubes.blockSize.y);
1042
FILLRECTANGLE(w, dr,
1044
fx, fy, w->cubes.blockSize.x, incAt);
1045
FILLRECTANGLE(w, dr,
1047
fx + w->cubes.blockSize.x - incAt, fy,
1034
1048
incAt, w->cubes.blockSize.y);
1035
1049
FILLRECTANGLE(w, dr,
1036
1050
w->cubes.inverseGC,
1037
fromdx, fromdy + w->cubes.blockSize.y - incAt,
1051
fx, fy + w->cubes.blockSize.y - incAt,
1038
1052
w->cubes.blockSize.x, incAt);
1040
1054
for (inc = incAt; inc < incTo; inc += incAt) {
1041
int xR = fromdx + inc, yR = fromdy + inc;
1055
int xR = fx + inc, yR = fy + inc;
1042
1056
int wR = w->cubes.blockSize.x - 2 * inc;
1043
1057
int hR = w->cubes.blockSize.y - 2 * inc;
1127
ResetBlocks(CubesWidget w)
1131
w->cubes.sizeRect = w->cubes.sizeX * w->cubes.sizeY;
1132
w->cubes.sizeBlock = w->cubes.sizeRect * w->cubes.sizeZ;
1133
if (w->cubes.blockOfPosition)
1134
free((void *) w->cubes.blockOfPosition);
1135
if (!(w->cubes.blockOfPosition = (int *)
1136
malloc(sizeof (int) * w->cubes.sizeBlock))) {
1137
DISPLAY_ERROR("Not enough memory, exiting.");
1141
free((void *) startPosition);
1142
if (!(startPosition = (int *)
1143
malloc(sizeof (int) * w->cubes.sizeBlock))) {
1144
DISPLAY_ERROR("Not enough memory, exiting.");
1147
w->cubes.spacePosition = w->cubes.sizeBlock - 1;
1148
w->cubes.blockOfPosition[w->cubes.sizeBlock - 1] = 0;
1149
for (i = 1; i < w->cubes.sizeBlock; i++)
1150
w->cubes.blockOfPosition[i - 1] = i;
1152
w->cubes.currentPosition = -1;
1153
w->cubes.started = False;
1157
1141
EraseFrame(const CubesWidget w, Pixmap dr)
1159
1143
FILLRECTANGLE(w, dr, w->cubes.inverseGC,
1599
RandomizeBlocks(CubesWidget w)
1583
ResetBlocks(CubesWidget w)
1601
if (w->cubes.currentPosition >= 0)
1603
w->cubes.cheat = False;
1604
/* First interchange blocks an even number of times */
1605
/* Must be at least 3x2 or 2x2x2 */
1606
if ((w->cubes.sizeX > 2 && (w->cubes.sizeY > 1 || w->cubes.sizeZ > 1)) ||
1607
(w->cubes.sizeY > 2 && (w->cubes.sizeX > 1 || w->cubes.sizeZ > 1)) ||
1608
(w->cubes.sizeZ > 2 && (w->cubes.sizeX > 1 || w->cubes.sizeY > 1)) ||
1609
(w->cubes.sizeX == 2 && w->cubes.sizeY == 2 && w->cubes.sizeZ == 2)) {
1612
for (pos = 0; pos < w->cubes.sizeBlock; pos++) {
1613
int randomPos = pos;
1615
while (randomPos == pos) {
1616
randomPos = NRAND(w->cubes.sizeBlock);
1618
count += ExchangeBlocks(w, pos, randomPos);
1621
!ExchangeBlocks(w, 0, 1) &&
1622
!ExchangeBlocks(w, w->cubes.sizeBlock - 2,
1623
w->cubes.sizeBlock - 1)) {
1624
DISPLAY_WARNING("RandomizeBlocks: should not get here");
1628
XFlush(XtDisplay(w));
1631
/* randomly position space */
1632
/* Idea for this came from "puzzle" by Don Bennett, HP Labs */
1636
s = Column(w, w->cubes.spacePosition);
1637
e = NRAND(w->cubes.sizeX);
1638
for (n = 0; n < e - s; n++)
1639
(void) MoveCubesDir(w, LEFT, INSTANT);
1640
for (n = 0; n < s - e; n++)
1641
(void) MoveCubesDir(w, RIGHT, INSTANT);
1642
s = Row(w, w->cubes.spacePosition);
1643
e = NRAND(w->cubes.sizeY);
1644
for (n = 0; n < e - s; n++)
1645
(void) MoveCubesDir(w, TOP, INSTANT);
1646
for (n = 0; n < s - e; n++)
1647
(void) MoveCubesDir(w, BOTTOM, INSTANT);
1648
s = Stack(w, w->cubes.spacePosition);
1649
e = NRAND(w->cubes.sizeZ);
1650
for (n = 0; n < e - s; n++)
1651
(void) MoveCubesDir(w, OUTWARDS, INSTANT);
1652
for (n = 0; n < s - e; n++)
1653
(void) MoveCubesDir(w, INWARDS, INSTANT);
1655
SetCubes(w, CUBES_RANDOMIZE);
1658
/* Now move the space around randomly */
1659
if (w->cubes.sizeX > 1 || w->cubes.sizeY > 1 || w->cubes.sizeZ > 1) {
1660
int big = w->cubes.sizeBlock + NRAND(2);
1661
int lastDirection = -1;
1662
int randomDirection;
1664
SetCubes(w, CUBES_RESET);
1671
randomDirection = NRAND(COORD);
1675
if ((randomDirection < 4 && (randomDirection + 2) % 4 != lastDirection) ||
1676
(randomDirection >= 4 && randomDirection + ((randomDirection % 2) ? -1 : 1) != lastDirection) ||
1677
(w->cubes.sizeX == 1 && w->cubes.sizeY == 1) ||
1678
(w->cubes.sizeY == 1 && w->cubes.sizeZ == 1) ||
1679
(w->cubes.sizeZ == 1 && w->cubes.sizeX == 1)) {
1680
if (MoveCubesDir(w, randomDirection, INSTANT))
1681
lastDirection = randomDirection;
1687
SetCubes(w, CUBES_RANDOMIZE);
1690
if (CheckSolved(w)) {
1691
SetCubes(w, CUBES_SOLVED);
1587
w->cubes.sizeRect = w->cubes.sizeX * w->cubes.sizeY;
1588
w->cubes.sizeBlock = w->cubes.sizeRect * w->cubes.sizeZ;
1589
if (w->cubes.blockOfPosition)
1590
free((void *) w->cubes.blockOfPosition);
1591
if (!(w->cubes.blockOfPosition = (int *)
1592
malloc(sizeof (int) * w->cubes.sizeBlock))) {
1593
DISPLAY_ERROR("Not enough memory, exiting.");
1597
free((void *) startPosition);
1598
if (!(startPosition = (int *)
1599
malloc(sizeof (int) * w->cubes.sizeBlock))) {
1600
DISPLAY_ERROR("Not enough memory, exiting.");
1603
w->cubes.spacePosition = w->cubes.sizeBlock - 1;
1604
w->cubes.blockOfPosition[w->cubes.sizeBlock - 1] = 0;
1605
for (i = 1; i < w->cubes.sizeBlock; i++)
1606
w->cubes.blockOfPosition[i - 1] = i;
1608
w->cubes.currentPosition = -1;
1609
w->cubes.started = False;
1827
RandomizeBlocks(CubesWidget w)
1829
if (w->cubes.currentPosition >= 0)
1831
w->cubes.cheat = False;
1832
/* First interchange blocks an even number of times */
1833
/* Must be at least 3x2 or 2x2x2 */
1834
if ((w->cubes.sizeX > 2 && (w->cubes.sizeY > 1 || w->cubes.sizeZ > 1)) ||
1835
(w->cubes.sizeY > 2 && (w->cubes.sizeX > 1 || w->cubes.sizeZ > 1)) ||
1836
(w->cubes.sizeZ > 2 && (w->cubes.sizeX > 1 || w->cubes.sizeY > 1)) ||
1837
(w->cubes.sizeX == 2 && w->cubes.sizeY == 2 && w->cubes.sizeZ == 2)) {
1840
for (pos = 0; pos < w->cubes.sizeBlock; pos++) {
1841
int randomPos = pos;
1843
while (randomPos == pos) {
1844
randomPos = NRAND(w->cubes.sizeBlock);
1846
count += ExchangeBlocks(w, pos, randomPos);
1849
!ExchangeBlocks(w, 0, 1) &&
1850
!ExchangeBlocks(w, w->cubes.sizeBlock - 2,
1851
w->cubes.sizeBlock - 1)) {
1852
DISPLAY_WARNING("RandomizeBlocks: should not get here");
1856
XFlush(XtDisplay(w));
1859
/* randomly position space */
1860
/* Idea for this came from "puzzle" by Don Bennett, HP Labs */
1864
s = Column(w, w->cubes.spacePosition);
1865
e = NRAND(w->cubes.sizeX);
1866
for (n = 0; n < e - s; n++)
1867
(void) MoveCubesDir(w, LEFT, INSTANT);
1868
for (n = 0; n < s - e; n++)
1869
(void) MoveCubesDir(w, RIGHT, INSTANT);
1870
s = Row(w, w->cubes.spacePosition);
1871
e = NRAND(w->cubes.sizeY);
1872
for (n = 0; n < e - s; n++)
1873
(void) MoveCubesDir(w, TOP, INSTANT);
1874
for (n = 0; n < s - e; n++)
1875
(void) MoveCubesDir(w, BOTTOM, INSTANT);
1876
s = Stack(w, w->cubes.spacePosition);
1877
e = NRAND(w->cubes.sizeZ);
1878
for (n = 0; n < e - s; n++)
1879
(void) MoveCubesDir(w, OUTWARDS, INSTANT);
1880
for (n = 0; n < s - e; n++)
1881
(void) MoveCubesDir(w, INWARDS, INSTANT);
1883
SetCubes(w, CUBES_RANDOMIZE);
1886
/* Now move the space around randomly */
1887
if (w->cubes.sizeX > 1 || w->cubes.sizeY > 1 || w->cubes.sizeZ > 1) {
1888
int big = w->cubes.sizeBlock + NRAND(2);
1889
int lastDirection = -1;
1890
int randomDirection;
1892
SetCubes(w, CUBES_RESET);
1899
randomDirection = NRAND(COORD);
1903
if ((randomDirection < 4 && (randomDirection + 2) % 4 != lastDirection) ||
1904
(randomDirection >= 4 && randomDirection + ((randomDirection % 2) ? -1 : 1) != lastDirection) ||
1905
(w->cubes.sizeX == 1 && w->cubes.sizeY == 1) ||
1906
(w->cubes.sizeY == 1 && w->cubes.sizeZ == 1) ||
1907
(w->cubes.sizeZ == 1 && w->cubes.sizeX == 1)) {
1908
if (MoveCubesDir(w, randomDirection, INSTANT))
1909
lastDirection = randomDirection;
1915
SetCubes(w, CUBES_RANDOMIZE);
1918
if (CheckSolved(w)) {
1919
SetCubes(w, CUBES_SOLVED);
1910
1924
SolveBlocks(CubesWidget w)
1912
1926
if (CheckSolved(w) || w->cubes.currentPosition >= 0)