mirror of
https://github.com/TextPlace/CoreTextPlace.git
synced 2025-07-09 21:25:32 +00:00
initial version
This commit is contained in:
commit
6dfe7129c4
15 changed files with 614 additions and 0 deletions
25
logic/board.ts
Normal file
25
logic/board.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import type { SectionData, SectionPosition } from "../types/section.ts";
|
||||
import type {
|
||||
BoardConfig,
|
||||
BoardData,
|
||||
CharacterPosition,
|
||||
} from "../types/board.ts";
|
||||
import { createSection } from "./section.ts";
|
||||
|
||||
export function createBoard(config: BoardConfig): BoardData {
|
||||
const sections: SectionData[][] = Array(config.ySections).map((_, sy) =>
|
||||
Array(config.xSections).map((_, sx) => createSection({ sx, sy }, config))
|
||||
);
|
||||
|
||||
return { config, sections };
|
||||
}
|
||||
|
||||
export function locateSection(
|
||||
{ x, y }: CharacterPosition,
|
||||
config: BoardConfig
|
||||
): SectionPosition {
|
||||
return {
|
||||
sx: Math.floor(x / config.sectionWidth),
|
||||
sy: Math.floor(y / config.sectionHeight),
|
||||
};
|
||||
}
|
20
logic/character.ts
Normal file
20
logic/character.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
const segmenter = new Intl.Segmenter("en", { granularity: "grapheme" });
|
||||
const cjkRegex =
|
||||
/[\p{Unified_Ideograph}\u30A0-\u30FF\u3040-\u309F\u31F0-\u31FF]/u;
|
||||
const printableASCIIRegex = /^[\x20-\x7E]$/;
|
||||
|
||||
export function getCharacterWidth(ch: string): number {
|
||||
const segments = [...segmenter.segment(ch)];
|
||||
if (segments.length !== 1)
|
||||
throw new Error(
|
||||
`Expected exactly one grapheme cluster, got ${segments.length}.`
|
||||
);
|
||||
|
||||
const matchesASCII = ch.match(printableASCIIRegex);
|
||||
const matchesCJK = ch.match(cjkRegex);
|
||||
|
||||
if (!matchesASCII && !matchesCJK) throw new Error(`Invalid character: ${ch}`);
|
||||
|
||||
// TODO: Support Emojis.
|
||||
return matchesCJK ? 2 : 1;
|
||||
}
|
44
logic/section.ts
Normal file
44
logic/section.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { getCharacterWidth } from "../mod.ts";
|
||||
import type { BoardConfig } from "../types/board.ts";
|
||||
import { BoardChange } from "../types/change.ts";
|
||||
import type { SectionData, SectionPosition } from "../types/section.ts";
|
||||
|
||||
export function createSection(
|
||||
{ sx, sy }: SectionPosition,
|
||||
boardConfig: BoardConfig
|
||||
): SectionData {
|
||||
const offsetX = sx * boardConfig.sectionWidth;
|
||||
const offsetY = sy * boardConfig.sectionHeight;
|
||||
|
||||
const ch: string[][] = Array(boardConfig.sectionHeight).fill(
|
||||
Array(boardConfig.sectionWidth).fill(boardConfig.defaultCh)
|
||||
);
|
||||
const color: string[][] = Array(boardConfig.sectionHeight).fill(
|
||||
Array(boardConfig.sectionWidth).fill(boardConfig.defaultColor)
|
||||
);
|
||||
const bgColor: string[][] = Array(boardConfig.sectionHeight).fill(
|
||||
Array(boardConfig.sectionWidth).fill(boardConfig.defaultBgColor)
|
||||
);
|
||||
const width: number[][] = Array(boardConfig.sectionHeight).fill(
|
||||
Array(boardConfig.sectionWidth).fill(boardConfig.defaultWidth)
|
||||
);
|
||||
|
||||
return { offsetX, offsetY, ch, color, bgColor, width };
|
||||
}
|
||||
|
||||
export function applyChange(change: BoardChange, section: SectionData) {
|
||||
const xInSection = change.x - section.offsetX;
|
||||
const yInSection = change.y - section.offsetY;
|
||||
|
||||
if (change.ch) {
|
||||
const chWidth = getCharacterWidth(change.ch);
|
||||
section.ch[yInSection][xInSection] = change.ch;
|
||||
section.width[yInSection][xInSection] = chWidth;
|
||||
}
|
||||
if (change.color) {
|
||||
section.color[yInSection][xInSection] = change.color;
|
||||
}
|
||||
if (change.bg_color) {
|
||||
section.bgColor[yInSection][xInSection] = change.bg_color;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue