npm package: @polarfoxdev/straenge-riddle-generator
Description: Riddle generation library with Web Worker support for Angular and other web apps
Author: Jakob Neumann
Latest version: 1.1.0

# @polarfoxdev/straenge-riddle-generator

A TypeScript library for generating word riddles for the [Stränge/Strängar](https://github.com/polarfoxDev/strangui) puzzle game, with Web Worker support for non-blocking UI in Angular and other web applications.

> **Note:** This library is specifically designed to generate riddles compatible with the Stränge/Strängar game format. It is not intended for general-purpose riddle generation.

## Installation

```bash
npm install @polarfoxdev/straenge-riddle-generator
```

## Usage

### Option 1: Using Web Worker (Recommended for UI apps)

The Web Worker approach prevents the riddle generation from blocking your main thread, keeping your UI responsive.

#### Angular Setup

1. **Create a worker file** in your Angular project (e.g., `src/app/riddle.worker.ts`):

```typescript
/// <reference lib="webworker" />

// Re-export the worker implementation
import "@polarfoxdev/straenge-riddle-generator/worker";
```

2. **Update angular.json** to include web worker support (Angular CLI usually handles this automatically).

3. **Use the service** in your component or service:

```typescript
import { Component, OnDestroy } from '@angular/core';
import { 
  RiddleGeneratorService, 
  RiddleResult 
} from '@polarfoxdev/straenge-riddle-generator';

@Component({
  selector: 'app-riddle',
  template: `
    <button (click)="generateRiddle()" [disabled]="generating">
      {{ generating ? 'Generating...' : 'Generate Riddle' }}
    </button>
    <div *ngIf="progress">Attempt: {{ progress }}</div>
  `
})
export class RiddleComponent implements OnDestroy {
  private riddleService: RiddleGeneratorService;
  generating = false;
  progress = 0;

  constructor() {
    // Create the worker using Angular's worker syntax
    const worker = new Worker(new URL('./riddle.worker', import.meta.url));
    this.riddleService = new RiddleGeneratorService(worker);
  }

  async generateRiddle(): Promise<void> {
    this.generating = true;
    this.progress = 0;

    try {
      const riddle = await this.riddleService.generate(
        'LOESUNG',  // Super solution (6+ characters)
        ['WORT', 'HAUS', 'BAUM', 'TIER', 'WALD', 'BERG'],  // Word pool
        {
          timeoutMs: 30000,
          maxAttempts: 500,
          onProgress: (attempt) => {
            this.progress = attempt;
          }
        }
      );

      console.log('Generated riddle:', riddle);
      // Use riddle.nodes, riddle.words, riddle.edges to render
    } catch (error) {
      console.error('Failed to generate riddle:', error);
    } finally {
      this.generating = false;
    }
  }

  ngOnDestroy(): void {
    this.riddleService.terminate();
  }
}
```

### Option 2: Direct Usage (Simple, but blocks main thread)

For server-side usage or when blocking is acceptable:

```typescript
import { tryGenerateRiddle, Riddle } from '@polarfoxdev/straenge-riddle-generator';

const riddle: Riddle | null = tryGenerateRiddle(
  'LOESUNG',
  ['WORT', 'HAUS', 'BAUM', 'TIER', 'WALD', 'BERG']
);

if (riddle) {
  console.log('Success!');
  // Access riddle.nodes, riddle.words, riddle.edges
}
```

## API Reference

### RiddleGeneratorService

```typescript
class RiddleGeneratorService {
  constructor(worker: Worker);
  
  generate(
    superSolution: string,
    wordPool: string[],
    options?: GenerateOptions
  ): Promise<RiddleResult>;
  
  terminate(): void;
}
```

### GenerateOptions

```typescript
interface GenerateOptions {
  timeoutMs?: number;      // Default: 30000 (30 seconds)
  maxAttempts?: number;    // Default: 1000
  onProgress?: (attempt: number) => void;
  locale?: string;         // Default: 'en' (see Language Support below)
}
```

### Language Support

The library uses Unicode grapheme segmentation to properly handle characters in different languages. By default, English ('en') locale is used, but you can configure it for other languages:

#### With Web Worker

Pass the locale in the options when generating:

```typescript
const riddle = await riddleService.generate(
  'LÖSUNG',
  ['WÖRTER', 'BÄUME', 'GRÜN'],
  {
    locale: 'de'  // German locale for proper umlaut handling
  }
);
```

#### Direct Usage (without Web Worker)

Use the `configure` function before generating:

```typescript
import { configure, tryGenerateRiddle } from '@polarfoxdev/straenge-riddle-generator';

// Set the locale before generating
configure({ locale: 'de' });

const riddle = tryGenerateRiddle('LÖSUNG', ['WÖRTER', 'BÄUME']);
```

#### Supported Locales

Any valid BCP 47 language tag is supported. Common examples:

| Locale | Language |
|--------|----------|
| `'en'` | English (default) |
| `'de'` | German |
| `'fr'` | French |
| `'es'` | Spanish |
| `'th'` | Thai |
| `'ko'` | Korean |
| `'ja'` | Japanese |
| `'ar'` | Arabic |

### RiddleResult

```typescript
interface RiddleResult {
  nodes: NodeResult[];   // 6x8 grid of nodes
  words: WordResult[];   // All words in the riddle
  edges: EdgeResult[];   // Connections between letters
}

interface NodeResult {
  row: number;
  col: number;
  letter: string | null;
  wordIndex: number;        // Index into words array
  isSuperSolution: boolean;
}

interface WordResult {
  word: string;
  isSuperSolution: boolean;
  color: string;
  used: boolean;
}

interface EdgeResult {
  node1: { row: number; col: number };
  node2: { row: number; col: number };
  wordIndex: number;
}
```

### Constants

```typescript
const RIDDLE_WIDTH = 6;   // Grid width
const RIDDLE_HEIGHT = 8;  // Grid height
```

## Requirements

- Super solution must be at least 6 characters long
- Word pool should contain enough words to fill the remaining grid space
- Words are automatically converted to uppercase and special characters are normalized

## Building from Source

```bash
cd ts
npm install
npm run build
```

## License

MIT