contra-renderer/www/js/interpreterCommon.ts

365 lines
10 KiB
TypeScript

import { DancerIdentity, Rotation } from "./danceCommon.js";
import { Hand } from "./rendererConstants.js";
export enum PositionKind {
Circle = "Circle",
ShortLines = "ShortLines",
};
// Which of the four corners of a circle.
// Note that "Left" is the left side of the set, not left from the dancer's PoV,
// so, in improper, the Robin starts in the BottomLeft.
enum CirclePositionEnum {
TopLeft = "TopLeft",
BottomLeft = "BottomLeft",
BottomRight = "BottomRight",
TopRight = "TopRight",
}
export enum CircleSide {
Top = "Top",
Bottom = "Bottom",
Left = "Left",
Right = "Right",
}
export type CircleSideOrCenter = CircleSide | "Center";
export class CirclePosition {
public static readonly TopLeft = new CirclePosition(CirclePositionEnum.TopLeft);
public static readonly BottomLeft = new CirclePosition(CirclePositionEnum.BottomLeft);
public static readonly BottomRight = new CirclePosition(CirclePositionEnum.BottomRight);
public static readonly TopRight = new CirclePosition(CirclePositionEnum.TopRight);
private readonly enumValue: CirclePositionEnum;
private constructor(enumValue: CirclePositionEnum) {
this.enumValue = enumValue;
}
private static enumValueToNumber(enumValue: CirclePositionEnum) : number {
switch (enumValue) {
case CirclePositionEnum.TopLeft:
return 0;
case CirclePositionEnum.BottomLeft:
return 1;
case CirclePositionEnum.BottomRight:
return 2;
case CirclePositionEnum.TopRight:
return 3;
}
}
private static numberToEnumValue(num: number) : CirclePositionEnum {
if (num < 0 || num > 3) {
num %= 4;
if (num < 0) num += 4;
}
return [
CirclePositionEnum.TopLeft,
CirclePositionEnum.BottomLeft,
CirclePositionEnum.BottomRight,
CirclePositionEnum.TopRight,
][num];
}
private static get(enumValue: CirclePositionEnum) : CirclePosition {
return [
CirclePosition.TopLeft,
CirclePosition.BottomLeft,
CirclePosition.BottomRight,
CirclePosition.TopRight,
][this.enumValueToNumber(enumValue)];
}
public circleRight(places?: number) : CirclePosition {
return CirclePosition.get(CirclePosition.numberToEnumValue(CirclePosition.enumValueToNumber(this.enumValue) - (places ?? 1)));
}
public circleLeft(places?: number) : CirclePosition {
return CirclePosition.get(CirclePosition.numberToEnumValue(CirclePosition.enumValueToNumber(this.enumValue) + (places ?? 1)));
}
public swapAcross() : CirclePosition {
return [
CirclePosition.TopRight,
CirclePosition.BottomRight,
CirclePosition.BottomLeft,
CirclePosition.TopLeft,
][CirclePosition.enumValueToNumber(this.enumValue)];
}
public swapUpAndDown() : CirclePosition {
return [
CirclePosition.BottomLeft,
CirclePosition.TopLeft,
CirclePosition.TopRight,
CirclePosition.BottomRight,
][CirclePosition.enumValueToNumber(this.enumValue)];
}
public swapDiagonal() : CirclePosition {
return this.swapAcross().swapUpAndDown();
}
public facingCenterRotation() : Rotation {
return (45 + 90 * CirclePosition.enumValueToNumber(this.enumValue)) % 360;
}
public topBottomSide() : CircleSide.Top | CircleSide.Bottom {
return this.enumValue === CirclePositionEnum.TopLeft || this.enumValue === CirclePositionEnum.TopRight
? CircleSide.Top
: CircleSide.Bottom;
}
public leftRightSide() : CircleSide.Left | CircleSide.Right {
return this.enumValue === CirclePositionEnum.TopLeft || this.enumValue === CirclePositionEnum.BottomLeft
? CircleSide.Left
: CircleSide.Right;
}
public isTop() : boolean {
return this.topBottomSide() === CircleSide.Top;
}
public isLeft() : boolean {
return this.leftRightSide() === CircleSide.Left;
}
public isOnLeftLookingAcross() : boolean {
return this.enumValue === CirclePositionEnum.TopRight || this.enumValue === CirclePositionEnum.BottomLeft;
}
public isOnLeftLookingUpAndDown() : boolean {
return this.enumValue === CirclePositionEnum.TopLeft || this.enumValue === CirclePositionEnum.BottomRight;
}
public facingAcross() : Facing.Left | Facing.Right {
return this.isLeft() ? Facing.Right : Facing.Left;
}
public facingOut() : Facing.Left | Facing.Right {
return this.isLeft() ? Facing.Left : Facing.Right;
}
public facingUpOrDown() : Facing.Up | Facing.Down {
return this.isTop() ? Facing.Down : Facing.Up;
}
public toString() : string {
return this.enumValue.toString();
}
}
enum ShortLinesPositionEnum {
FarLeft = "FarLeft",
MiddleLeft = "MiddleLeft",
MiddleRight = "MiddleRight",
FarRight = "FarRight",
}
export class ShortLinesPosition {
public static readonly FarLeft = new ShortLinesPosition(ShortLinesPositionEnum.FarLeft);
public static readonly MiddleLeft = new ShortLinesPosition(ShortLinesPositionEnum.MiddleLeft);
public static readonly MiddleRight = new ShortLinesPosition(ShortLinesPositionEnum.MiddleRight);
public static readonly FarRight = new ShortLinesPosition(ShortLinesPositionEnum.FarRight);
private readonly enumValue: ShortLinesPositionEnum;
private constructor(enumValue: ShortLinesPositionEnum) {
this.enumValue = enumValue;
}
private static enumValueToNumber(enumValue: ShortLinesPositionEnum) : number {
switch (enumValue) {
case ShortLinesPositionEnum.FarLeft:
return 0;
case ShortLinesPositionEnum.MiddleLeft:
return 1;
case ShortLinesPositionEnum.MiddleRight:
return 2;
case ShortLinesPositionEnum.FarRight:
return 3;
}
}
private static numberToEnumValue(num: number) : ShortLinesPositionEnum {
if (num < 0 || num > 3) {
num %= 4;
if (num < 0) num += 4;
}
return [
ShortLinesPositionEnum.FarLeft,
ShortLinesPositionEnum.MiddleLeft,
ShortLinesPositionEnum.MiddleRight,
ShortLinesPositionEnum.FarRight,
][num];
}
private static get(enumValue: ShortLinesPositionEnum) : ShortLinesPosition {
return [
ShortLinesPosition.FarLeft,
ShortLinesPosition.MiddleLeft,
ShortLinesPosition.MiddleRight,
ShortLinesPosition.FarRight,
][this.enumValueToNumber(enumValue)];
}
public swapOnSide() : ShortLinesPosition {
return [
ShortLinesPosition.MiddleLeft,
ShortLinesPosition.FarLeft,
ShortLinesPosition.FarRight,
ShortLinesPosition.MiddleRight,
][ShortLinesPosition.enumValueToNumber(this.enumValue)];
}
public swapSides() : ShortLinesPosition {
return [
ShortLinesPosition.FarRight,
ShortLinesPosition.MiddleRight,
ShortLinesPosition.MiddleLeft,
ShortLinesPosition.FarLeft,
][ShortLinesPosition.enumValueToNumber(this.enumValue)];
}
public isMiddle() : boolean {
return this.enumValue === ShortLinesPositionEnum.MiddleRight || this.enumValue === ShortLinesPositionEnum.MiddleLeft;
}
public leftRightSide() : CircleSide.Left | CircleSide.Right {
return this.enumValue === ShortLinesPositionEnum.FarLeft || this.enumValue === ShortLinesPositionEnum.MiddleLeft
? CircleSide.Left
: CircleSide.Right;
}
public isLeft() : boolean {
return this.leftRightSide() === CircleSide.Left;
}
public facingSide() : Facing.Left | Facing.Right {
return this.isLeft() === this.isMiddle() ? Facing.Left : Facing.Right;
}
public toString() : string {
return this.enumValue.toString();
}
}
export enum Facing {
CenterOfCircle = "CenterOfCircle",
// for star left/right
LeftInCircle = "LeftInCircle",
RightInCircle = "RightInCircle",
Up = "Up",
Down = "Down",
Left = "Left",
Right = "Right",
}
export function oppositeFacing(facing: Facing.Up | Facing.Down | Facing.Left | Facing.Right | Facing.LeftInCircle | Facing.RightInCircle) {
switch (facing) {
case Facing.LeftInCircle:
return Facing.RightInCircle;
case Facing.RightInCircle:
return Facing.LeftInCircle;
case Facing.Up:
return Facing.Down;
case Facing.Down:
return Facing.Up;
case Facing.Left:
return Facing.Right;
case Facing.Right:
return Facing.Left;
}
}
export enum StarGrip {
HandsAcross = "HandsAcross",
WristGrip = "WristGrip",
}
export enum HandTo {
LeftInCircle = "LeftInCircle",
RightInCircle = "RightInCircle",
AcrossCircle = "AcrossCircle",
DiagonalAcrossCircle = "DiagonalAcrossCircle",
LeftDiagonalAcrossCircle = "LeftDiagonalAcrossCircle",
RightDiagonalAcrossCircle = "RightDiagonalAcrossCircle",
DancerForward = "DancerForward",
DancerLeft = "DancerLeft",
DancerRight = "DancerRight",
}
export interface HandConnection {
to: HandTo,
hand: Hand,
}
export enum BalanceWeight {
Forward = "Forward",
Backward = "Backward",
Left = "Left",
Right = "Right",
}
export enum DancerDistance {
Normal = "Normal",
Compact = "Compact", // allemande, etc.
// Swings asymmetrical, but some dances may have the Lark do a swing as a Robin or vice versa,
// especially any dance with Larks Swing or Robins Swing.
SwingLark = "SwingLark",
SwingRobin = "SwingRobin",
}
export enum LongLines {
Forward = "Forward",
}
export type SemanticPosition = {
kind: PositionKind.Circle,
setOffset?: number,
lineOffset?: number,
which: CirclePosition,
facing: Facing,
hands?: Map<Hand, HandConnection>,
balance?: BalanceWeight,
dancerDistance?: DancerDistance,
longLines?: LongLines,
} | {
kind: PositionKind.ShortLines,
setOffset?: number,
lineOffset?: number,
which: ShortLinesPosition,
facing: Facing,
hands?: Map<Hand, HandConnection>,
balance?: BalanceWeight,
dancerDistance?: DancerDistance,
};
export const handsInCircle = new Map<Hand, HandConnection>([
[Hand.Left, {
to: HandTo.LeftInCircle,
hand: Hand.Right,
}],
[Hand.Right, {
to: HandTo.RightInCircle,
hand: Hand.Left,
}],
]);
export const handsFourImproper: Map<DancerIdentity, SemanticPosition> = new Map<DancerIdentity, SemanticPosition>([
[DancerIdentity.OnesLark, {
kind: PositionKind.Circle,
which: CirclePosition.TopLeft,
facing: Facing.CenterOfCircle,
hands: handsInCircle,
}],
[DancerIdentity.OnesRobin, {
kind: PositionKind.Circle,
which: CirclePosition.TopRight,
facing: Facing.CenterOfCircle,
hands: handsInCircle,
}],
[DancerIdentity.TwosLark, {
kind: PositionKind.Circle,
which: CirclePosition.BottomRight,
facing: Facing.CenterOfCircle,
hands: handsInCircle,
}],
[DancerIdentity.TwosRobin, {
kind: PositionKind.Circle,
which: CirclePosition.BottomLeft,
facing: Facing.CenterOfCircle,
hands: handsInCircle,
}],
]);