This is AliceDoc.m in view mode; [Download] [Up]
/* Generated by Interface Builder */
#import "AliceDoc.h"
#import "AliceApp.h"
#import "CubeView.h"
#import "CubePlane.h"
#import "Plane.h"
extern "Objective-C" {
#import "BasicApp.h"
#import <objc/List.h>
#import <objc/Storage.h>
#import <appkit/Window.h>
#import <appkit/Matrix.h>
#import <appkit/MenuCell.h>
}
extern "C" {
#import <strings.h>
}
typedef struct _Action {
CubeCoord plane;
CubeDir dir;
} Action;
#define ZAlloc(CLASS) [CLASS allocFromZone:[self zone]]
#ifndef DITCHDAY
static id RandGen;
static const int RandTurns = 8;
#else
#define CAPITAL 0x20
static const char Scrambler[] = "BmWjHbWLkkoGcggx";
static const int RandTurns = 16;
#endif
static const CubeInt SidesShown = 3;
@implementation AliceDoc
+ initialize
{
#ifndef DITCHDAY
RandGen = [ZAlloc(Random) init];
#endif
[super initialize];
[self setContentsClass:[CubeView class]];
return self;
}
- getWindow
{
myCube = new Cube;
for (CubeInt d=0; d < SidesShown; d++) {
#ifdef THREED
Plane *newPlane = myCube->plane(2*d+1);
#else
Plane *newPlane = myCube->plane(2*d+1, T);
#endif
[contents addSubview:[ZAlloc(CubePlane)
initPlane:newPlane tag:d]];
}
[contents resize:self];
undoActions = [ZAlloc(Storage) initCount:0
elementSize:sizeof(Action)
description:"{ii}"];
[super getWindow];
[window addToEventMask:NX_KEYDOWNMASK];
return self;
}
- free
{
[undoActions free];
return [super free];
}
- reset:sender
{
myCube->reset();
[undoActions empty];
scrambled = NO;
return [self test:self];
}
- scramble:sender
{
int n;
[self reset:sender];
[contents setAutodisplay:NO];
for (n=0; n < RandTurns; n++) {
#ifndef DITCHDAY
[self twist:(int)[RandGen randMax:(CubeNSides-1)]
:getDir([RandGen rand])];
#else
char code = Scrambler[n];
CubeDir dir = (code & CAPITAL) ? 1 : 0;
[self doTwist:code :dir];
#endif
[undoActions empty];
}
[contents setAutodisplay:YES];
scrambled = YES;
return [self test:self];
}
- unscramble:sender
{
while ([self undo:self]) {
NXPing();
}
return [self test:self];
}
- undo:sender
{
int count;
if (count = [undoActions count]) {
Action *last;
last = (Action*)[undoActions elementAt:(count-1)];
[self twist:last->plane :last->dir];
[undoActions removeLastElement]; /* Don't redo this! */
[undoActions removeLastElement]; /* Don't undo this! */
return [self test:self];
}
return nil;
}
- test:sender
{
if (scrambled && [undoActions count] && !myCube->test()) {
[NXApp successPanel:self];
scrambled = NO;
}
return [contents update];
}
/* Modify State */
- twist:(CubeCoord) plane :(CubeDir) rot
{
Action next;
#ifdef THREED
CubeAxis axis2 = XYZTMAX; /* Use default */
Plane *twister = myCube->plane(plane);
#else
CubeAxis axis2 = getAxis(rot);
Plane *twister = myCube->plane(plane,axis2);
#endif
#ifdef DEBUG1
printf("Twist:%d :%d\n",plane,rot);
#endif
twister[LO].rotate(getDir(rot),axis2);
#ifndef THREED
twister[HI].rotate(getDir(rot),axis2);
#endif
delete twister;
next.plane = plane; /* Undo List */
next.dir = revDir(rot);
[undoActions addElement:&next];
return self;
}
- rotate:(CubeCoord) plane :(CubeDir) dir
{
[self twist:plane :dir];
[self twist:otherSide(plane) :dir];
return self;
}
/* Rotate */
- rotateX:sender
{
CubeDir tag = [sender selectedTag];
[self rotate:X0 :tag];
return [self test:self];
}
- rotateY:sender
{
CubeDir tag = [sender selectedTag];
[self rotate:Y0 :tag];
return [self test:self];
}
- rotateZ:sender
{
CubeDir tag = [sender selectedTag];
[self rotate:Z0 :tag];
return [self test:self];
}
- rotateT:sender
{
CubeDir tag = [sender selectedTag];
[self rotate:T0 :tag];
return [self test:self];
}
#define POS_MASK ('\010')
inline CubePos parsePos(CubeInt tag) {return (tag & POS_MASK) ? 1 : 0;}
inline CubeDir parseDir(CubeInt tag) {return tag & (~POS_MASK);}
/* Twist */
- twistX:sender
{
CubeInt tag = [sender selectedTag];
[self twist:X0+parsePos(tag) :parseDir(tag)];
return [self test:self];
}
- twistY:sender
{
CubeInt tag = [sender selectedTag];
[self twist:Y0+parsePos(tag) :parseDir(tag)];
return [self test:self];
}
- twistZ:sender
{
CubeInt tag = [sender selectedTag];
[self twist:Z0+parsePos(tag) :parseDir(tag)];
return [self test:self];
}
- twistT:sender
{
CubeInt tag = [sender selectedTag];
[self twist:T0+parsePos(tag) :parseDir(tag)];
return [self test:self];
}
#define COORD_MASK 0x01F /* Just use the bottom 31 */
#define WRAP(C) ((C & (COORD_MASK))-1) /* a =0, b = 1, ... x=31 */
/* 6 per plane, 3 per position */
#define NROTS (3)
/* key Equivalents */
- doTwist:(unsigned short) charCode :(short)dir
{
unsigned char code = WRAP(charCode);
CubeCoord coord = (code / NROTS) % CubeNCoords;
CubeAxis axis = code % NROTS;
if (axis == getAxis(coord)) axis = T;
[self twist:coord :setDir(axis,dir)];
return [self test:self];
}
- doRotate:(unsigned short) charCode :(short)dir
{
unsigned char code = WRAP(charCode);
CubeCoord coord = (code / NROTS) % CubeNCoords;
CubeAxis axis = code % NROTS;
if (axis == getAxis(coord)) axis = T;
[self rotate:coord :setDir(axis,dir)];
return [self test:self];
}
/* Delegate Methods */
- (BOOL)validateCommand:menuCell
/*
* Validates whether a menu command that Document responds to
* is valid at the current time.
*/
{
SEL action = [menuCell action];
if (action == @selector(reset:) || action == @selector(scramble:) ) {
return YES;
} else if (action == @selector(undo:) || action==@selector(unscramble:)) {
return (BOOL) [undoActions count];
}
return YES;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.