Skip to content

Commit

Permalink
v3.4.20
Browse files Browse the repository at this point in the history
gruppler committed Sep 3, 2024
2 parents d0d7fa4 + af05aaa commit 1ee66d5
Showing 7 changed files with 102 additions and 58 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ptn-ninja",
"version": "3.4.19",
"version": "3.4.20",
"description": "An editor and viewer for Portable Tak Notation",
"productName": "PTN Ninja",
"author": "Craig Laparo <gruppler+github@gmail.com>",
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
@@ -250,7 +250,7 @@ The structure of the URL is as follows:

`https://ptn.ninja/<PTN>&<param1>=<value1>&<param2>=<value2>[...]`

To get a shortened URL, send a POST request to `https://url.ptn.ninja/short` with request body `{ ptn, params (optional) }` where `ptn` is a string, and `params` is an optional object containing any of the parameters below. If the request is valid, you'll receive the complete shortenend URL as plain text in response.
To get a shortened URL, send a POST request to `https://url.ptn.ninja/short` with request body `{ ptn, params (optional) }` where `ptn` is a string, and `params` is an optional object containing any of the parameters below. If the request is valid, you'll receive the complete shortenend URL as plain text in response. If the URL is not accessed within 30 days, it will be deleted.

### URL Parameters

3 changes: 1 addition & 2 deletions src/Game/PTN/Tag.js
Original file line number Diff line number Diff line change
@@ -36,8 +36,7 @@ export const formats = {
flats: /^\d+$/,
flats1: /^\d+$/,
flats2: /^\d+$/,
clock:
/^\d+min(\+\d+sec)$|^((((\d\s+)?\d\d?:)?\d\d?:)?\d\d?\s*)?(\+(((\d\s+)?\d\d?:)?\d\d?:)?\d\d?)?$/,
clock: /^[^"]+$/,
date: /^\d{4}\.\d\d?\.\d\d?$/,
event: /^[^"]+$/,
komi: /^-?\d*(\.5)?$/,
32 changes: 30 additions & 2 deletions src/Game/base.js
Original file line number Diff line number Diff line change
@@ -78,6 +78,14 @@ export default class GameBase {
return params;
}

// Split multi-game PTN into separate games
static split(ptn) {
return ptn.match(
/^\s*(\[\w+\s"[^"]*"\]\s*)+((\{[^}]*\})*[/.\s\da-hCFRS!?"'><+-]+)+/gm
);
}

// #region Init
init({
ptn,
name,
@@ -145,8 +153,10 @@ export default class GameBase {
this.notes = {};
this.warnings = [];

// Parse HEAD
//#region Parse HEAD

try {
// Parse tags from PTN
if (ptn) {
let item, key;

@@ -174,6 +184,7 @@ export default class GameBase {
}
}

// Parse tags from JSON
if (tags) {
each(tags, (value, key) => {
if (value) {
@@ -195,6 +206,7 @@ export default class GameBase {
});
}

// Parse datetime
if (this.tags.date) {
this.datetime = Tag.toDate(
this.tags.date.value,
@@ -204,17 +216,21 @@ export default class GameBase {
this.datetime = new Date();
}

// Get size
if (this.tags.size) {
this.size = this.tags.size.value;
} else {
if (this.tags.tps) {
// Derive from TPS
this.size = this.tags.tps.value.size;
this.tags.size = Tag.parse(`[Size "${this.size}"]`);
} else {
let error = "Missing board size";
if (ptn) {
// Fail if initializing from PTN
throw new Error(error);
} else {
// Use default size otherwise
console.warn(error);
this.warnings.push(error);
this.size = this.defaultSize;
@@ -223,10 +239,12 @@ export default class GameBase {
}
}

// Sanitize opening
if (!this.tags.opening) {
this.tags.opening = Tag.parse('[Opening "swap"]');
}

// Parse TPS
if (this.tags.tps) {
this.hasTPS = true;
this.firstMoveNumber = this.tags.tps.value.linenum;
@@ -271,8 +289,10 @@ export default class GameBase {
this.updateConfig();
this.board = new Board(this, null, this.board ? this.board.output : null);

// Parse BODY
//#region Parse BODY

if (ptn) {
// Parse moves from PTN
let item, ply;
let branch = null;
let move = new Move({
@@ -422,6 +442,7 @@ export default class GameBase {
delete item.ptn;
}
} else if (moves) {
// Parse moves from JSON
if (comments) {
this.parseJSONComments(comments, -1);
}
@@ -431,6 +452,8 @@ export default class GameBase {
return handleError(error);
}

//#region Init Game

if (!this.moves[0]) {
this.moves[0] = new Move({
game: this,
@@ -451,6 +474,7 @@ export default class GameBase {
this.name = this.generateName();
}

// Init TPS
if (this.tags.tps || this.editingTPS) {
this.board.doTPS(this.editingTPS);
}
@@ -518,6 +542,8 @@ export default class GameBase {
}
}

//#region Methods

get minState() {
return this.board.minState;
}
@@ -735,6 +761,8 @@ export default class GameBase {
}
}

//#region Output

toString(options) {
options = Object.assign(
{
59 changes: 34 additions & 25 deletions src/components/drawers/BotSuggestions.vue
Original file line number Diff line number Diff line change
@@ -202,35 +202,39 @@
</template>

<!-- Topaz -->
<template v-else-if="botSettings.bot === 'topaz'">
<div v-else-if="botSettings.bot === 'topaz'" class="relative-position">
<q-btn
v-if="!suggestions.length && !isGameEnd"
@click="loadingTopazMoves ? null : requestTopazSuggestions()"
:percentage="progressTopazAnalysis"
class="full-width"
color="primary"
icon="board"
:label="$t('analysis.Analyze Position')"
:loading="loadingTopazMoves"
:ripple="!loadingTopazMoves"
stretch
>
<template v-if="loadingTopazMoves">
<PlyChip
v-if="analyzingPly"
:ply="allPlies[analyzingPly.id]"
@click.stop="goToAnalysisPly"
no-branches
:done="analyzingPly.isDone"
style="text-transform: none"
/>
<q-spinner />
<q-btn :label="$t('Cancel')" @click.stop="terminateTopaz" flat />
</template>
<template v-else>
<q-icon name="board" left /><span class="block">{{
$t("analysis.Analyze Position")
}}</span>
</template>
</q-btn>
</template>
/>
<PlyChip
v-if="loadingTopazMoves && analyzingPly"
:ply="allPlies[analyzingPly.id]"
@click.stop="goToAnalysisPly"
no-branches
:done="analyzingPly.isDone"
class="absolute-left"
/>
<q-btn
v-if="loadingTopazMoves"
:label="$t('Cancel')"
@click.stop="terminateTopaz"
class="absolute-right"
:text-color="
$store.state.ui.theme.primaryDark ? 'textLight' : 'textDark'
"
stretch
flat
/>
</div>
</smooth-reflow>

<!-- Results -->
@@ -539,7 +543,7 @@ export default {
}
},
// MARK: Tiltak Cloud
//#region Tiltak Cloud
async analyzeGameTiltak() {
if (this.isOffline || !this.game.ptn.branchPlies.length) {
@@ -690,7 +694,7 @@ export default {
return result;
},
// MARK: Tiltak WASM
//#region Tiltak WASM
initTiltakInteractive(force = false) {
if (force || !this.tiltakWorker) {
@@ -923,7 +927,7 @@ export default {
}
},
// MARK: Topaz
//#region Topaz
initTopaz(force = false) {
if (force || !this.topazWorker) {
@@ -1023,7 +1027,7 @@ export default {
}
},
// MARK: Init
//#region Init
init() {
// Load wasm bots
@@ -1095,8 +1099,13 @@ export default {
},
botSettings: {
handler(settings) {
// Save preferences
this.$store.dispatch("ui/SET_UI", ["botSettings", settings]);
// Update current position/bot hash
this.botSettingsHash = this.hashBotSettings(settings);
// Stop interactive analysis when switching bots
if (settings.bot !== "tiltak" && this.tiltakInteractive.isEnabled) {
this.tiltakInteractive.isEnabled = false;
}
2 changes: 1 addition & 1 deletion src/i18n/en-us/about.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# PTN Ninja

**Version [3.4.19](https://github.com/gruppler/PTN-Ninja/releases)**
**Version [3.4.20](https://github.com/gruppler/PTN-Ninja/releases)**

This is an editor and viewer for [Portable Tak Notation (PTN)](https://ustak.org/portable-tak-notation/). It aims to be...

60 changes: 34 additions & 26 deletions src/store/game/actions.js
Original file line number Diff line number Diff line change
@@ -444,11 +444,41 @@ export const OPEN_FILES = async function ({ dispatch, state }, files) {
resolve;
}
};

const onInit = (game) => {
games.push(game);
finish();
};

const parseGame = (ptn, name) => {
const onError = (error, plyID) => {
console.warn(
`Encountered an error in "${name}" at plyID:`,
plyID,
error
);
notifyError(`${name}: ${error.message}`);
finish();
};

const index = state.list.findIndex((g) => g.name === name);
if (index < 0 || this.state.ui.openDuplicate !== "replace") {
try {
new Game({
ptn,
name,
onError,
onInit,
});
} catch (error) {
console.error("Invalid game:", name, error);
}
} else {
dispatch("REPLACE_GAME", { index, ptn });
finish();
}
};

files = Array.from(files);
files = files.filter((file) => file && /(\.ptn|\.txt)+$/i.test(file.name));
if (!files.length) {
@@ -462,32 +492,10 @@ export const OPEN_FILES = async function ({ dispatch, state }, files) {
let reader = new FileReader();
reader.onload = (event) => {
const name = file.name.replace(/(\.ptn|\.txt)+$/, "");
const index = state.list.findIndex((g) => g.name === name);
const ptn = event.target.result;
const onError = (error, plyID) => {
console.warn(
`Encountered an error in "${name}" at plyID:`,
plyID,
error
);
notifyError(`${name}: ${error.message}`);
finish();
};
if (index < 0 || this.state.ui.openDuplicate !== "replace") {
try {
new Game({
ptn,
name,
onError,
onInit,
});
} catch (error) {
console.error("Invalid game:", name, error);
}
} else {
dispatch("REPLACE_GAME", { index, ptn });
finish();
}
const games = Game.split(event.target.result);
games.forEach((ptn, i) => {
parseGame(ptn, `${name} - Game ${i + 1}`);
});
};
reader.onerror = notifyError;
reader.readAsText(file);

0 comments on commit 1ee66d5

Please sign in to comment.