diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index 121f7bb..0000000
--- a/.eslintrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "extends": "@pkmn"
-}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 31e8882..9b3acdb 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,30 +1,14 @@
-# This workflow will do an install of node dependencies, build the source code and run tests across different versions of node
-# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
-
name: Tests
-
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
-
jobs:
build:
-
runs-on: ubuntu-latest
-
- strategy:
- matrix:
- node-version: [14.x]
-
steps:
- - uses: actions/checkout@v2
- - name: Use Node.js ${{ matrix.node-version }}
- uses: Zarel/setup-node@patch-1
- with:
- node-version: ${{ matrix.node-version }}
+ - uses: actions/checkout@v3
- run: npm install
- - run: npm run test
- env:
- CI: true
+ - run: npm test
+ - run: npm run lint
diff --git a/.gitignore b/.gitignore
index 08cf3f7..dc5afd4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,27 @@
-node_modules/
-build/
+# Mac
.DS_Store
Thumbs.db
+.vscode
+
+# Zig
+zig-cache/
+zig-out/
+build/
+/docgen_tmp/
+
+# C
+*.o
+
+# JS
+coverage/
+node_modules/
+dist/
*package-lock.json
+*npm-debug.log
.eslintcache
.tsbuildinfo
-.vscode
-*-debug.log
+.parcel-cache/
+
+# Project
+logs/
+release/
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 66d6fbc..3469970 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2020-2022 pkmn contributors
+Copyright (c) 2020-2023 pkmn contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/README.md b/README.md
index ec13d15..69f51d3 100644
--- a/README.md
+++ b/README.md
@@ -22,16 +22,6 @@ perspective of the client. EPOké is designed to be useful in many domains, expo
information from replays, extending the Pokémon Showdown client tooltips/UI, or inside the engine
of a Pokemon AI.
-- [`@pkmn/epoke`](epoke): a wrapper around
- [`@pkmn/client`](https://github.com/pkmn/ps/tree/master/client) which ties together `@pkmn/gmd`,
- `@pkmn/predictor` and `@pkmn/spreads` to produce an enhanced client representation of a battle
-- [`@pkmn/gmd`](gmd): a reverse damage calculator built on top of
- [`@pkmn/dmg`](https://github.com/pkmn/dmg) to deduce information about a Pokémon's moveset based
- on the damage it deals or receives in battle
-- [`@pkmn/predictor`](predictor): logic which combines usage stats information from
- [`@pkmn/stats`](https://github.com/pkmn/stats) with minimal heuristics to predict likely instances
- of an opponent's team
-- [`@pkmn/spreads`](spreads): a lightweight, standalone package for manipulating and displaying
- stats, spreads, and ranges
+TODO
Everything in this repository is distributed under the terms of the [MIT License](LICENSE).
diff --git a/epoke/README.md b/epoke/README.md
index 4197e8b..a4279ca 100644
--- a/epoke/README.md
+++ b/epoke/README.md
@@ -1,67 +1,18 @@
-
![EPOké](https://pkmn.cc/EPOke.png)
-
# `@pkmn/epoke`
![Test Status](https://github.com/pkmn/EPOke/workflows/Tests/badge.svg)
![License](https://img.shields.io/badge/License-MIT-blue.svg)
-`@pkmn/epoke` extends [`@pkmn/client`](https://github.com/pkmn/ps/tree/master/client) with
-information from [`@pkmn/gmd`](../gmd), [`@pkmn/predictor`](../predictor), and
-[`@pkmn/spreads`](../spreads) to produce an enhanced client representation of a Pokémon battle.
-EPOké offers several key features over `@pkmn/client`:
-
-- **spread information**: `@pkmn/client` can determine information about a side's `stats` from the
- `|request|` protocol message and provides support for setting a side's `sets` to known values so
- that its state can be used with [`@pkmn/dmg`](https://github.com/pkmn/dmg) in a limited number of
- circumstances, but with EPOké `@pkmn/dmg` can *always* be used as it can additionally:
- - reverse the `stats` from `|request|` into a spread using `@pkmn/spreads`
- - track the `StatsRange` for a Pokémon, winnow it down with information from `@pkmn/gmd`, and
- finally, return the most likely estimate for the spread with help from `@pkmn/predictor` and
- usage stats
- - allow for a user to override predicted values for stats (while still maintaining accurate tracking)
-- **inferred state**: EPOké leverages `@pkmn/gmd` to deduce information about the battle state (eg.
- an opponent Pokémon's item or ability) on top of what is already known from `@pkmn/client`
-- **possible state instantiation**: EPOké provides the ability to generate possible instantiations
- of the simulator's [`State`](https://github.com/pkmn/ps/blob/master/sim/sim/state.ts) using the
- information it has collected and with help from `@pkmn/predictor` and usage stats
-
-If information in battle can be determined conclusively and without the help of anything in this
-repository it is in scope for `@pkmn/client`, everything else is the domain of `@pkmn/epoke`.
-
+TODO
## Installation
```sh
$ npm install @pkmn/epoke
```
-Alternatively, as [detailed below](#browser), if you are using `@pkmn/epoke` in the browser and
-want a convenient way to get started, simply depend on a transpiled and minified version via
-[unpkg](https://unpkg.com/):
-
-```html
-
-```
-
## Usage
-FIXME
-
-```ts
-```
-
-### Browser
-
-The recommended way of using `@pkmn/epoke` in a web browser is to **configure your bundler**
-([Webpack](https://webpack.js.org/), [Rollup](https://rollupjs.org/),
-[Parcel](https://parceljs.org/), etc) to minimize it and package it with the rest of your
-application. If you do not use a bundler, a minified `index.umd.js` bundle is included in the
-package. You simply need to depend on `./node_modules/@pkmn/epoke/build/index.umd.js` in a
-`script` tag (which is what the unpkg shortcut above is doing), after which **`epoke` will be
-accessible as a global**:
-
-```html
-
-```
+TODO
## License
diff --git a/epoke/package.json b/epoke/package.json
index d8989d9..28aa2c4 100644
--- a/epoke/package.json
+++ b/epoke/package.json
@@ -1,53 +1,25 @@
{
"name": "@pkmn/epoke",
"version": "0.0.1",
+ "main": "build/index.js",
+ "types": "build/index.d.ts",
"description": "Enhanced client representation of a Pokémon battle",
"repository": "github:pkmn/EPOke",
"license": "MIT",
- "sideEffects": false,
- "main": "build/index.js",
- "module": "build/index.mjs",
- "types": "build/index.d.ts",
- "files": ["build"],
"publishConfig": {
"access": "public"
},
"dependencies": {
- "@pkmn/client": "^0.6.0",
- "@pkmn/data": "^0.7.0",
- "@pkmn/protocol": "^0.6.0",
- "@pkmn/spreads": "^0.1.0"
+ "@pkmn/spreads": "file:../spreads"
},
"scripts": {
"lint": "eslint --cache src --ext ts",
"fix": "eslint --fix src --ext ts",
"compile": "tsc -p .",
- "build": "npm run compile && tsup src/index.ts",
- "test": "jest",
- "prepare": "npm run build",
- "pretest": "npm run build",
- "posttest": "npm run lint"
- },
- "tsup": {
- "outDir": "build",
- "format": ["cjs", "esm"],
- "sourcemap": true,
- "dts": true,
- "clean": true
- },
- "jest": {
- "preset": "ts-jest",
- "testEnvironment": "node",
- "testPathIgnorePatterns": ["node_modules/", "build/"]
+ "build": "npm run compile",
+ "test": "vitest src"
},
"eslintConfig": {
- "extends": "@pkmn",
- "ignorePatterns": ["node_modules/", "build/"],
- "overrides": [{
- "files": ["src/index.ts"],
- "rules": {
- "@typescript-eslint/no-shadow": "off"
- }
- }]
+ "extends": "@pkmn"
}
}
diff --git a/epoke/src/client.ts b/epoke/src/client.ts
deleted file mode 100644
index 9c29852..0000000
--- a/epoke/src/client.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import {BoostsTable, ID, StatsTable, StatusName, TypeName} from '@pkmn/data';
-import {Range} from '@pkmn/spreads';
-import {Slot} from './index';
-
-interface Unknown {
- known?: T;
- override?: T;
- range?: Range;
-}
-
-export interface Battle {
- sides: [Side, Side];
- turn: number;
- lastDamage: Unknown;
- prng: readonly Unknown[];
-}
-
-export interface Side {
- active: Pokemon | undefined;
- pokemon: Unknown[];
- lastUsedMove: Unknown;
- lastSelectedMove: Unknown;
- lastSelectedIndex: Unknown<1 | 2 | 3 | 4 | undefined>;
-}
-
-export interface Pokemon {
- species: ID;
- types: readonly [TypeName, TypeName];
- level: number;
- hp: Unknown;
- status: StatusName | undefined;
- statusData: {sleep: Unknown; self: boolean; toxic: number};
- stats: Unknown;
- boosts: BoostsTable;
- moves: MoveSlot[];
- volatiles: Volatiles;
- stored: {
- species: ID;
- types: readonly [TypeName, TypeName];
- stats: Unknown;
- moves: Iterable>;
- };
- position: Slot;
-}
-
-export interface MoveSlot {
- id: Unknown;
- pp: Unknown;
- disabled?: Unknown;
-}
-
-export interface Volatiles {
- bide?: {duration: Unknown; damage: Unknown};
- thrashing?: {duration: Unknown; accuracy: Unknown};
- multihit?: boolean;
- flinch?: boolean;
- charging?: boolean;
- trapping?: {duration: Unknown};
- invulnerable?: boolean;
- confusion?: {duration: Unknown};
- mist?: boolean;
- focusenergy?: boolean;
- substitute?: {hp: Unknown};
- recharging?: boolean;
- rage?: {accuracy: Unknown};
- leechseed?: boolean;
- lightscreen?: boolean;
- reflect?: boolean;
- transform?: {player: 'p1' | 'p2'; slot: number};
-}
-
-// Doesnt extend or delegate to regular client (which )
-// Can't be used zero-copy with dmg
-
diff --git a/epoke/src/test/index.test.ts b/epoke/src/index.test.ts
similarity index 100%
rename from epoke/src/test/index.test.ts
rename to epoke/src/index.test.ts
diff --git a/epoke/src/index.ts b/epoke/src/index.ts
index 80113bf..e69de29 100644
--- a/epoke/src/index.ts
+++ b/epoke/src/index.ts
@@ -1,70 +0,0 @@
-import {BoostsTable, ID, StatsTable, StatusName, TypeName} from '@pkmn/data';
-
-export type Slot = 1 | 2 | 3 | 4 | 5 | 6;
-export type Battle = Gen1.Battle;
-export type Side = Gen1.Side;
-export type Pokemon = Gen1.Pokemon;
-export type MoveSlot = Gen1.MoveSlot;
-
-export namespace Gen1 {
- export interface Battle {
- sides: Iterable;
- turn: number;
- lastDamage: number;
- prng: readonly number[];
- }
-
- export interface Side {
- active: Pokemon | undefined;
- pokemon: Iterable;
- lastUsedMove: ID | undefined;
- lastSelectedMove: ID | undefined;
- lastSelectedIndex: 1 | 2 | 3 | 4 | undefined;
- }
-
- export interface Pokemon {
- species: ID;
- types: readonly [TypeName, TypeName];
- level: number;
- hp: number;
- status: StatusName | undefined;
- statusData: {sleep: number; self: boolean; toxic: number};
- stats: StatsTable;
- boosts: BoostsTable;
- moves: Iterable;
- volatiles: Volatiles;
- stored: {
- species: ID;
- types: readonly [TypeName, TypeName];
- stats: StatsTable;
- moves: Iterable>;
- };
- position: Slot;
- }
-
- export interface MoveSlot {
- id: ID;
- pp: number;
- disabled?: number;
- }
-
- export interface Volatiles {
- bide?: {duration: number; damage: number};
- thrashing?: {duration: number; accuracy: number};
- multihit?: unknown;
- flinch?: unknown;
- charging?: unknown;
- trapping?: {duration: number};
- invulnerable?: unknown;
- confusion?: {duration: number};
- mist?: unknown;
- focusenergy?: unknown;
- substitute?: {hp: number};
- recharging?: unknown;
- rage?: {accuracy: number};
- leechseed?: unknown;
- lightscreen?: unknown;
- reflect?: unknown;
- transform?: {player: 'p1' | 'p2'; slot: number};
- }
-}
diff --git a/epoke/test b/epoke/test
deleted file mode 100644
index e8b6c61..0000000
--- a/epoke/test
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-try {
- require('source-map-support').install();
-} catch (err) {
- if (err.code !== 'MODULE_NOT_FOUND') throw err;
-}
-
-const diff = require('json-diff');
-
-const {Dex, TeamValidator, RandomPlayerAI, BattleStreams, PRNG} = require('@pkmn/sim');
-const {Battle} = require('@pkmn/client');
-
-const {Generations} = require('@pkmn/data');
-
-const prng = new PRNG();
-const seed = prng.seed;
-const formatid = 'gen4ou'; // TODO
-const validator = new TeamValidator(formatid, Dex);
-// TODO: alternatively, pull teams from a team DB...
-const teamA = dex.packTeam(predictor.generateTeam(formatid, prng, validator));
-const teamB = dex.packTeam(predictor.generateTeam(formatid, prng, validator));
-
-const battleStream = new BattleStreams.BattleStream();
-const streams = BattleStreams.getPlayerStreams(battleStream);
-
-const p1 = new RandomPlayerAI(streams.p1);
-const p2 = new RandomPlayerAI(streams.p2);
-
-void p1.start();
-void p2.start();
-
-const gens = new Generations(Dex);
-const battle = new Battle(gens);
-
-void (async () => {
- for await (const chunk of streams.omniscient) {
- battle.add(chunk);
- // diff.diffString(battle.toJSON(), battleStream.battle);
- }
-})();
-
-void streams.omniscient.write(`>start ${JSON.stringify({formatid})}
->player p1 ${JSON.stringify({name: 'Player A', team: teamA})}
->player p2 ${JSON.stringify({name: 'Player B', team: teamB})}`);
\ No newline at end of file
diff --git a/epoke/tsconfig.json b/epoke/tsconfig.json
index 61b458c..36e101e 100644
--- a/epoke/tsconfig.json
+++ b/epoke/tsconfig.json
@@ -1,6 +1,7 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
+ "outDir": "build",
"tsBuildInfoFile": ".tsbuildinfo"
},
"include": ["src/**/*"]
diff --git a/epoke/vitest.config.ts b/epoke/vitest.config.ts
new file mode 100644
index 0000000..dbfd933
--- /dev/null
+++ b/epoke/vitest.config.ts
@@ -0,0 +1,9 @@
+import {defineConfig} from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ watch: false,
+ globals: true,
+ exclude: ['node_modules', 'build'],
+ },
+});
diff --git a/gmd/README.md b/gmd/README.md
index 64973ee..8b4a98b 100644
--- a/gmd/README.md
+++ b/gmd/README.md
@@ -3,7 +3,7 @@
![Test Status](https://github.com/pkmn/EPOke/workflows/Tests/badge.svg)
![License](https://img.shields.io/badge/License-MIT-blue.svg)
-FIXME
+TODO
## Installation
@@ -11,34 +11,9 @@ FIXME
$ npm install @pkmn/gmd
```
-Alternatively, as [detailed below](#browser), if you are using `@pkmn/gmd` in the browser and
-want a convenient way to get started, simply depend on a transpiled and minified version via
-[unpkg](https://unpkg.com/):
-
-```html
-
-```
-
## Usage
-FIXME
-
-```ts
-```
-
-### Browser
-
-The recommended way of using `@pkmn/gmd` in a web browser is to **configure your bundler**
-([Webpack](https://webpack.js.org/), [Rollup](https://rollupjs.org/),
-[Parcel](https://parceljs.org/), etc) to minimize it and package it with the rest of your
-application. If you do not use a bundler, a minified `index.umd.js` bundle is included in the
-package. You simply need to depend on `./node_modules/@pkmn/gmd/build/index.umd.js` in a
-`script` tag (which is what the unpkg shortcut above is doing), after which **`gmd` will be
-accessible as a global**:
-
-```html
-
-```
+TODO
## License
diff --git a/gmd/package.json b/gmd/package.json
index cc7bd34..a889c9e 100644
--- a/gmd/package.json
+++ b/gmd/package.json
@@ -1,14 +1,11 @@
{
"name": "@pkmn/gmd",
"version": "0.0.1",
+ "main": "build/index.js",
+ "types": "build/index.d.ts",
"description": "Reverse Pokémon damage calculator",
"repository": "github:pkmn/EPOke",
"license": "MIT",
- "sideEffects": false,
- "main": "build/index.js",
- "module": "build/index.mjs",
- "types": "build/index.d.ts",
- "files": ["build"],
"publishConfig": {
"access": "public"
},
@@ -16,22 +13,10 @@
"lint": "eslint --cache src --ext ts",
"fix": "eslint --fix src --ext ts",
"compile": "tsc -p .",
- "build": "npm run compile && tsup src/index.ts",
- "test": "jest",
- "prepare": "npm run build",
- "pretest": "npm run build",
- "posttest": "npm run lint"
- },
- "tsup": {
- "outDir": "build",
- "format": ["cjs", "esm"],
- "sourcemap": true,
- "dts": true,
- "clean": true
+ "build": "npm run compile",
+ "test": "vitest src"
},
- "jest": {
- "preset": "ts-jest",
- "testEnvironment": "node",
- "testPathIgnorePatterns": ["node_modules/", "build/"]
+ "eslintConfig": {
+ "extends": "@pkmn"
}
}
diff --git a/gmd/tsconfig.json b/gmd/tsconfig.json
index 61b458c..36e101e 100644
--- a/gmd/tsconfig.json
+++ b/gmd/tsconfig.json
@@ -1,6 +1,7 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
+ "outDir": "build",
"tsBuildInfoFile": ".tsbuildinfo"
},
"include": ["src/**/*"]
diff --git a/gmd/vitest.config.ts b/gmd/vitest.config.ts
new file mode 100644
index 0000000..dbfd933
--- /dev/null
+++ b/gmd/vitest.config.ts
@@ -0,0 +1,9 @@
+import {defineConfig} from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ watch: false,
+ globals: true,
+ exclude: ['node_modules', 'build'],
+ },
+});
diff --git a/package.json b/package.json
index b42ea2e..031d057 100644
--- a/package.json
+++ b/package.json
@@ -3,21 +3,15 @@
"repository": "github:pkmn/EPOke",
"license": "MIT",
"devDependencies": {
- "@pkmn/eslint-config": "^2.12.0",
- "@types/jest": "^29.2.3",
- "@types/node": "^18.11.9",
- "@typescript-eslint/eslint-plugin": "^5.43.0",
- "@typescript-eslint/parser": "^5.43.0",
- "eslint": "^8.28.0",
- "eslint-plugin-import": "^2.26.0",
- "eslint-plugin-jest": "^27.1.5",
- "jest": "^29.3.1",
+ "@pkmn/eslint-config": "^5.3.0",
+ "@types/jest": "^29.5.6",
+ "@types/node": "^20.8.9",
+ "eslint": "^8.52.0",
"subpkg": "^4.1.0",
- "ts-jest": "^29.0.3",
- "tsup": "^6.5.0",
- "typescript": "^4.9.3"
+ "vitest": "^0.34.6",
+ "typescript": "^5.2.2"
},
- "subPackages": ["spreads", "epoke"],
+ "subPackages": ["epoke", "gmd", "predictor", "spreads"],
"scripts": {
"lint": "subpkg run lint",
"fix": "subpkg run fix",
diff --git a/predictor/README.md b/predictor/README.md
index ff06b5d..e4c01b4 100644
--- a/predictor/README.md
+++ b/predictor/README.md
@@ -3,7 +3,7 @@
![Test Status](https://github.com/pkmn/EPOke/workflows/Tests/badge.svg)
![License](https://img.shields.io/badge/License-MIT-blue.svg)
-FIXME
+TODO
## Installation
@@ -11,34 +11,9 @@ FIXME
$ npm install @pkmn/predictor
```
-Alternatively, as [detailed below](#browser), if you are using `@pkmn/predictor` in the browser and
-want a convenient way to get started, simply depend on a transpiled and minified version via
-[unpkg](https://unpkg.com/):
-
-```html
-
-```
-
## Usage
-FIXME
-
-```ts
-```
-
-### Browser
-
-The recommended way of using `@pkmn/predictor` in a web browser is to **configure your bundler**
-([Webpack](https://webpack.js.org/), [Rollup](https://rollupjs.org/),
-[Parcel](https://parceljs.org/), etc) to minimize it and package it with the rest of your
-application. If you do not use a bundler, a minified `index.umd.js` bundle is included in the
-package. You simply need to depend on `./node_modules/@pkmn/predictor/build/index.umd.js` in a
-`script` tag (which is what the unpkg shortcut above is doing), after which **`predictor` will be
-accessible as a global**:
-
-```html
-
-```
+TODO
## License
diff --git a/predictor/package.json b/predictor/package.json
index 21cb77b..7bf7236 100644
--- a/predictor/package.json
+++ b/predictor/package.json
@@ -1,14 +1,11 @@
{
"name": "@pkmn/predictor",
"version": "0.0.1",
+ "main": "build/index.js",
+ "types": "build/index.d.ts",
"description": "Library for predicting likely instances of an opponent's Pokémon team",
"repository": "github:pkmn/EPOke",
"license": "MIT",
- "sideEffects": false,
- "main": "build/index.js",
- "module": "build/index.mjs",
- "types": "build/index.d.ts",
- "files": ["build"],
"publishConfig": {
"access": "public"
},
@@ -16,22 +13,10 @@
"lint": "eslint --cache src --ext ts",
"fix": "eslint --fix src --ext ts",
"compile": "tsc -p .",
- "build": "npm run compile && tsup src/index.ts",
- "test": "jest",
- "prepare": "npm run build",
- "pretest": "npm run build",
- "posttest": "npm run lint"
- },
- "tsup": {
- "outDir": "build",
- "format": ["cjs", "esm"],
- "sourcemap": true,
- "dts": true,
- "clean": true
+ "build": "npm run compile",
+ "test": "vitest src"
},
- "jest": {
- "preset": "ts-jest",
- "testEnvironment": "node",
- "testPathIgnorePatterns": ["node_modules/", "build/"]
+ "eslintConfig": {
+ "extends": "@pkmn"
}
-}
+}
\ No newline at end of file
diff --git a/predictor/src/test/index.test.ts b/predictor/src/index.test.ts
similarity index 100%
rename from predictor/src/test/index.test.ts
rename to predictor/src/index.test.ts
diff --git a/predictor/src/random.ts b/predictor/src/random.ts
deleted file mode 100644
index e0001ff..0000000
--- a/predictor/src/random.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-export class Random {
- seed: number;
-
- static seed(n = 4 /* https://xkcd.com/221/ */) {
- // Hash: https://burtleburtle.net/bob/hash/integer.html
- n = n ^ 61 ^ (n >>> 16);
- n = n + (n << 3);
- n = n ^ (n >>> 4);
- n = Math.imul(n, 0x27d4eb2d);
- n = n ^ (n >>> 15);
- return n >>> 0;
- }
-
- constructor(seed = Random.seed()) {
- this.seed = seed;
- }
-
- // Mulberry32: https://gist.github.com/tommyettinger/46a874533244883189143505d203312c
- next(min?: number, max?: number) {
- if (min) min = Math.floor(min);
- if (max) max = Math.floor(max);
-
- let z = (this.seed += 0x6d2b79f5 | 0);
- z = Math.imul(z ^ (z >>> 15), z | 1);
- z = z ^ (z + Math.imul(z ^ (z >>> 7), z | 61));
- z = (z ^ (z >>> 14)) >>> 0;
- const n = z / 2 ** 32;
-
- if (min === undefined) return n;
- if (!max) return Math.floor(n * min);
- return Math.floor(n * (max - min)) + min;
- }
-
- shuffle(arr: T[]) {
- for (let i = arr.length - 1; i > 0; i--) {
- const j = Math.floor(this.next() * (i + 1));
- [arr[i], arr[j]] = [arr[j], arr[i]];
- }
- return arr;
- }
-
- sample(arr: T[], remove = false) {
- if (arr.length === 0) throw new RangeError('Cannot sample an empty array');
- const index = this.next(arr.length);
- const val = arr[index];
- if (remove) {
- arr[index] = arr[arr.length - 1];
- arr.pop();
- }
- if (val === undefined && !Object.prototype.hasOwnProperty.call(arr, index)) {
- throw new RangeError('Cannot sample a sparse array');
- }
- return val;
- }
-}
diff --git a/predictor/src/test/random.test.ts b/predictor/src/test/random.test.ts
deleted file mode 100644
index 11451e5..0000000
--- a/predictor/src/test/random.test.ts
+++ /dev/null
@@ -1,102 +0,0 @@
-import {Random} from '../random';
-
-describe('Random', () => {
- test('next', () => {
- let r = new Random(42);
- const q = new Random(42);
- let n = 0;
- for (let i = 0; i <= 100; i++) {
- n = r.next();
- expect(n).toBeGreaterThanOrEqual(0);
- expect(n).toBeLessThan(1);
- expect(n).toEqual(q.next());
- }
-
- r = new Random();
- n = 0;
- for (let i = 0; i <= 100; i++) {
- if (r.next(2) < 1) n++;
- }
- expect(n).toBeGreaterThanOrEqual(45);
- expect(n).toBeLessThanOrEqual(55);
-
- r = new Random();
- n = 0;
- for (let i = 0; i <= 100; i++) {
- if (r.next(10, 265) < 227) n++;
- }
- expect(n).toBeGreaterThanOrEqual(80);
- expect(n).toBeLessThanOrEqual(90);
- });
-
- test('sample', () => {
- let r = new Random();
- let a: string[] = [];
- expect(() => r.sample(a)).toThrow(RangeError);
-
- r = new Random();
- a[30] = 'hello';
- expect(() => {
- for (let i = 0; i < 100; i++) {
- r.sample(a);
- }
- }).toThrow(RangeError);
-
- r = new Random();
- a = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'];
- delete a[9];
- expect(() => {
- for (let i = 0; i < 100; i++) {
- r.sample(a);
- }
- }).toThrow(RangeError);
-
- r = new Random();
- for (let i = 0; i < 10; ++i) {
- expect(r.sample(['a'])).toBe('a');
- }
-
- r = new Random();
- a = ['a', 'b', 'c', 'd', 'e'];
- const o = {a: 0, b: 0, c: 0, d: 0, e: 0};
- for (let i = 0; i < 1000; ++i) {
- o[r.sample(a) as keyof typeof o]++;
- }
- for (const k of a) {
- expect(o[k as keyof typeof o]).toBeGreaterThanOrEqual(170);
- expect(o[k as keyof typeof o]).toBeLessThanOrEqual(230);
- }
-
- r = new Random();
- a = ['x', 'x', 'y'];
- const p = {x: 0, y: 0};
- for (let i = 0; i < 1000; ++i) {
- p[r.sample(a) as keyof typeof p]++;
- }
- expect(p.x).toBeGreaterThanOrEqual(630);
- expect(p.x).toBeLessThanOrEqual(710);
- expect(p.y).toBeGreaterThanOrEqual(290);
- expect(p.y).toBeLessThanOrEqual(370);
-
- r = new Random(5);
- const q = new Random(5);
- const b = [{}, {}, {}, {}, {}, {}, {}, {}];
- for (let i = 0; i < 10; ++i) {
- expect(r.sample(b)).toBe(b[q.next(b.length)]);
- }
- });
-
- test('shuffle', () => {
- let r = new Random();
- expect(r.shuffle([])).toEqual([]);
- const a = [1, 2, 3, 4, 5];
- const b = a.slice();
-
- r = new Random(45);
- const q = new Random(45);
- expect(r.shuffle(a)).toEqual(q.shuffle(b));
- expect(a).toEqual(b);
-
- expect(a).not.toEqual([1, 2, 3, 4, 5]);
- });
-});
diff --git a/predictor/tsconfig.json b/predictor/tsconfig.json
index 61b458c..36e101e 100644
--- a/predictor/tsconfig.json
+++ b/predictor/tsconfig.json
@@ -1,6 +1,7 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
+ "outDir": "build",
"tsBuildInfoFile": ".tsbuildinfo"
},
"include": ["src/**/*"]
diff --git a/predictor/vitest.config.ts b/predictor/vitest.config.ts
new file mode 100644
index 0000000..dbfd933
--- /dev/null
+++ b/predictor/vitest.config.ts
@@ -0,0 +1,9 @@
+import {defineConfig} from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ watch: false,
+ globals: true,
+ exclude: ['node_modules', 'build'],
+ },
+});
diff --git a/spreads/package.json b/spreads/package.json
index ef4b67c..280a71a 100644
--- a/spreads/package.json
+++ b/spreads/package.json
@@ -15,15 +15,15 @@
"dependencies": {
"@pkmn/types": "^3.0.0"
},
+ "devDependencies": {
+ "tsup": "^7.2.0"
+ },
"scripts": {
"lint": "eslint --cache src --ext ts",
"fix": "eslint --fix src --ext ts",
"compile": "tsc -p .",
"build": "npm run compile && tsup src/index.ts",
- "test": "jest",
- "prepare": "npm run build",
- "pretest": "npm run build",
- "posttest": "npm run lint"
+ "test": "vitest src/test"
},
"tsup": {
"outDir": "build",
@@ -32,9 +32,7 @@
"dts": true,
"clean": true
},
- "jest": {
- "preset": "ts-jest",
- "testEnvironment": "node",
- "testPathIgnorePatterns": ["node_modules/", "build/"]
+ "eslintConfig": {
+ "extends": "@pkmn"
}
-}
+}
\ No newline at end of file
diff --git a/spreads/src/common.ts b/spreads/src/common.ts
index ea688f5..68ba065 100644
--- a/spreads/src/common.ts
+++ b/spreads/src/common.ts
@@ -1,5 +1,6 @@
import {GenerationNum, StatID} from '@pkmn/types';
-import {STATS, NATURES, GEN, Generation} from './data';
+
+import {GEN, Generation, NATURES, STATS} from './data';
const STAT_ORDER = ['hp', 'atk', 'def', 'spa', 'spd', 'spe'] as const;
const RBY_STAT_ORDER = ['hp', 'atk', 'def', 'spa', 'spe'] as const;
@@ -9,7 +10,7 @@ export interface Range {
max: T;
}
-export function isRange(r: unknown | Range): r is Range {
+export function isRange(r: unknown): r is Range {
return 'min' in (r as Range);
}
diff --git a/spreads/src/data.ts b/spreads/src/data.ts
index 3e1924b..ae2a671 100644
--- a/spreads/src/data.ts
+++ b/spreads/src/data.ts
@@ -1,5 +1,5 @@
// This code is cribbed from @pkmn/data and @pkmn/dex: https://github.com/pkmn/ps
-import {StatsTable, NatureName, StatID, GenerationNum, ID} from '@pkmn/types';
+import {GenerationNum, ID, NatureName, StatID, StatsTable} from '@pkmn/types';
export function toID(text: any): ID {
if (text?.id) text = text.id;
diff --git a/spreads/src/spread-range.ts b/spreads/src/spread-range.ts
index 46190a7..5e6a1a1 100644
--- a/spreads/src/spread-range.ts
+++ b/spreads/src/spread-range.ts
@@ -1,15 +1,15 @@
-import {StatsTable, GenerationNum, NatureName, StatID} from '@pkmn/types';
+import {GenerationNum, NatureName, StatID, StatsTable} from '@pkmn/types';
import {
+ Range,
displayRange,
getNatureFromPlusMinus,
isRange,
parseRange,
- Range,
statOrder,
} from './common';
-import {GEN, STATS, NATURES, Generation} from './data';
-import {Spread, SpreadTable, SpreadDisplayOptions} from './spread';
+import {GEN, Generation, NATURES, STATS} from './data';
+import {Spread, SpreadDisplayOptions, SpreadTable} from './spread';
import {StatsRange} from './stats-range';
// eslint-disable-next-line max-len
diff --git a/spreads/src/spread.ts b/spreads/src/spread.ts
index 3462f7b..3dba81a 100644
--- a/spreads/src/spread.ts
+++ b/spreads/src/spread.ts
@@ -1,8 +1,8 @@
-import {StatsTable, NatureName} from '@pkmn/types';
+import {NatureName, StatsTable} from '@pkmn/types';
-import {STATS, NATURES, GEN, Generation} from './data';
-import {Stats} from './stats';
+import {GEN, Generation, NATURES, STATS} from './data';
import {SpreadRange} from './spread-range';
+import {Stats} from './stats';
export interface SpreadTable {
nature?: NatureName;
diff --git a/spreads/src/stats-range.ts b/spreads/src/stats-range.ts
index 2cb7889..d280b40 100644
--- a/spreads/src/stats-range.ts
+++ b/spreads/src/stats-range.ts
@@ -1,18 +1,18 @@
import {StatsTable} from '@pkmn/types';
import {
+ Range,
StatsDisplayOptions,
displayRange,
displayStats,
getNatureFromPlusMinus,
isRange,
parseRange,
- Range,
statOrder,
} from './common';
-import {STATS, Generation, GEN} from './data';
-import {Stats} from './stats';
+import {GEN, Generation, STATS} from './data';
import {SpreadRange} from './spread-range';
+import {Stats} from './stats';
export class StatsRange implements Range {
min: Stats;
diff --git a/spreads/src/stats.ts b/spreads/src/stats.ts
index 8ced6ae..748d292 100644
--- a/spreads/src/stats.ts
+++ b/spreads/src/stats.ts
@@ -1,7 +1,7 @@
-import {StatsTable, StatID, GenerationNum} from '@pkmn/types';
+import {GenerationNum, StatID, StatsTable} from '@pkmn/types';
import {StatsDisplayOptions, displayStats, getNatureFromPlusMinus} from './common';
-import {NATURES, STATS, GEN, Generation, Nature} from './data';
+import {GEN, Generation, NATURES, Nature, STATS} from './data';
import {Spread} from './spread';
import {StatsRange} from './stats-range';
diff --git a/spreads/src/test/runner.ts b/spreads/src/test/runner.ts
index fad553e..a10128c 100644
--- a/spreads/src/test/runner.ts
+++ b/spreads/src/test/runner.ts
@@ -2,9 +2,9 @@ import assert from 'assert';
import {GenerationNum, StatsTable} from '@pkmn/types';
-import {Stats} from '../stats';
-import {Spread} from '../spread';
import * as data from '../data';
+import {Spread} from '../spread';
+import {Stats} from '../stats';
class Random {
seed: number;
diff --git a/spreads/src/test/spread-range.test.ts b/spreads/src/test/spread-range.test.ts
index ee6d50d..ebbd5c8 100644
--- a/spreads/src/test/spread-range.test.ts
+++ b/spreads/src/test/spread-range.test.ts
@@ -1,4 +1,5 @@
import {NatureName} from '@pkmn/types';
+
import {SpreadRange} from '../spread-range';
const RANGE = new SpreadRange({
diff --git a/spreads/src/test/stats-range.test.ts b/spreads/src/test/stats-range.test.ts
index 95f55b7..a4e2972 100644
--- a/spreads/src/test/stats-range.test.ts
+++ b/spreads/src/test/stats-range.test.ts
@@ -1,7 +1,7 @@
/* eslint-disable jest/prefer-to-contain */
+import {Spread} from '../spread';
import {Stats} from '../stats';
import {StatsRange} from '../stats-range';
-import {Spread} from '../spread';
const RANGE = new StatsRange({
min: {hp: 360, atk: 367, def: 250, spa: 203, spd: 235, spe: 180},
diff --git a/spreads/src/test/stats.test.ts b/spreads/src/test/stats.test.ts
index 03cd7cb..8eb9ab8 100644
--- a/spreads/src/test/stats.test.ts
+++ b/spreads/src/test/stats.test.ts
@@ -1,6 +1,6 @@
/* eslint-disable jest/no-conditional-expect */
-import {Stats, statToEV, statToIV} from '../stats';
import * as data from '../data';
+import {Stats, statToEV, statToIV} from '../stats';
import {run} from './runner';
diff --git a/spreads/tsconfig.json b/spreads/tsconfig.json
index 61b458c..36e101e 100644
--- a/spreads/tsconfig.json
+++ b/spreads/tsconfig.json
@@ -1,6 +1,7 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
+ "outDir": "build",
"tsBuildInfoFile": ".tsbuildinfo"
},
"include": ["src/**/*"]
diff --git a/spreads/vitest.config.ts b/spreads/vitest.config.ts
new file mode 100644
index 0000000..dbfd933
--- /dev/null
+++ b/spreads/vitest.config.ts
@@ -0,0 +1,9 @@
+import {defineConfig} from 'vitest/config';
+
+export default defineConfig({
+ test: {
+ watch: false,
+ globals: true,
+ exclude: ['node_modules', 'build'],
+ },
+});
diff --git a/tsconfig.json b/tsconfig.json
index b5ae039..524bccf 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -8,7 +8,7 @@
"incremental": true,
"lib": ["es2016", "dom"],
"module": "commonjs",
- "noEmit": true,
+ "noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"sourceMap": true,