Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abbreviate long input commands #16

Open
wants to merge 48 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
1144cc6
initial refactor renameData function
jmarkman Mar 10, 2021
6590a22
mostly pseudocode for move name formatting
jmarkman Mar 10, 2021
6877423
Merge branch 'main' of https://github.com/D4RKONION/FAT into abbrevia…
jmarkman Mar 10, 2021
cc5ec7d
Merge branch 'main' of https://github.com/D4RKONION/FAT into abbrevia…
jmarkman Mar 11, 2021
5e73fd5
finish initial impl. of shorthand rename func
jmarkman Mar 11, 2021
6b86c2c
Merge branch 'main' of https://github.com/D4RKONION/FAT into abbrevia…
jmarkman Mar 11, 2021
e471cd3
renameData function signature initial changes
jmarkman Mar 13, 2021
745d196
Merge branch 'main' of https://github.com/D4RKONION/FAT into abbrevia…
jmarkman Mar 13, 2021
6474d91
finish implementation of abbreviation func
jmarkman Mar 13, 2021
018a2aa
change variable for clarity based on feedback
jmarkman Mar 13, 2021
bcf2532
Merge branch 'main' of https://github.com/D4RKONION/FAT into abbrevia…
jmarkman Mar 14, 2021
46dfd13
apply PR feedback
jmarkman Mar 17, 2021
4209041
Merge branch 'main' of https://github.com/D4RKONION/FAT into abbrevia…
jmarkman Mar 17, 2021
310b69b
PR changes:
jmarkman Mar 19, 2021
404d482
start handling moves with modifying parentheses
jmarkman Mar 20, 2021
ecf50f2
rough work for implementing cross-game shorthand
jmarkman May 4, 2021
7af3906
Merge branch 'main' of https://github.com/D4RKONION/FAT into abbrevia…
jmarkman May 4, 2021
08ace03
Merge branch 'main' of https://github.com/D4RKONION/FAT into abbrevia…
jmarkman May 18, 2021
47abae5
begin refactoring code to address changes in data
jmarkman May 27, 2021
ae48589
hopefully last stages of shorthand for sf5
jmarkman Jun 6, 2021
50ad3d5
Additional changes to handle SF4 edge cases
jmarkman Jul 25, 2021
622b1e3
Merge branch 'main' of https://github.com/D4RKONION/FAT into abbrevia…
jmarkman Jul 25, 2021
58c33ab
Merge branch 'main' of https://github.com/D4RKONION/FAT into abbrevia…
jmarkman Oct 16, 2021
dd7d954
begin development of rules engine
jmarkman Oct 16, 2021
79b84f7
add rule for young zeku, refine formatter
jmarkman Oct 17, 2021
8d26ae2
Extract formatting logic into rules engine
jmarkman Jan 4, 2022
02828e8
Merge branch 'main' of https://github.com/D4RKONION/FAT into abbrevia…
jmarkman Jan 4, 2022
48b3ea0
Add final tweaks & rules for SF4 and Third Strike
jmarkman Feb 19, 2022
6b90b07
initial refactor renameData function
jmarkman Mar 10, 2021
cefd975
mostly pseudocode for move name formatting
jmarkman Mar 10, 2021
1e2dea2
finish initial impl. of shorthand rename func
jmarkman Mar 11, 2021
287747a
renameData function signature initial changes
jmarkman Mar 13, 2021
164207f
rebase main onto abbreviation branch
jmarkman Mar 13, 2021
433b207
change variable for clarity based on feedback
jmarkman Mar 13, 2021
79a2241
apply PR feedback
jmarkman Mar 17, 2021
93178cb
PR changes:
jmarkman Mar 19, 2021
3a25762
start handling moves with modifying parentheses
jmarkman Mar 20, 2021
94d832b
rough work for implementing cross-game shorthand
jmarkman May 4, 2021
1e43358
begin refactoring code to address changes in data
jmarkman May 27, 2021
f4bd360
hopefully last stages of shorthand for sf5
jmarkman Jun 6, 2021
46564e0
Additional changes to handle SF4 edge cases
jmarkman Jul 25, 2021
43560c7
begin development of rules engine
jmarkman Oct 16, 2021
6db0db6
add rule for young zeku, refine formatter
jmarkman Oct 17, 2021
ac279c3
Extract formatting logic into rules engine
jmarkman Jan 4, 2022
168feb9
Add final tweaks & rules for SF4 and Third Strike
jmarkman Feb 19, 2022
2b7c14c
Address pull request feedback and refactor
jmarkman May 8, 2022
d219057
Merge branch 'D4RKONION:main' into abbreviate-long-input-commands
jmarkman May 8, 2022
f914be7
Merge branch 'abbreviate-long-input-commands' of https://github.com/j…
jmarkman May 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/js/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export const setPlayer = (playerId: PlayerId, charName: PlayerData["name"]) =>
: "normal"
const playerData: PlayerData = {
name: charName,
frameData: helpCreateFrameDataJSON(frameDataState[charName].moves, dataDisplaySettingsState.moveNameType, dataDisplaySettingsState.inputNotationType, dataDisplaySettingsState.normalNotationType, stateToSet),
frameData: helpCreateFrameDataJSON(frameDataState[charName].moves, dataDisplaySettingsState, stateToSet),
stats: frameDataState[charName].stats,
vtState: stateToSet,
}
Expand Down
6 changes: 2 additions & 4 deletions src/js/pages/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,7 @@ const Settings = () => {
</IonSelect>
</IonItem>

{/* @Jon Uncomment this! */}
{/* <IonItem lines="full">
<IonItem lines="full">
<IonLabel>
<h2>Normal Notation</h2>
<p>Choose long or short normal names</p>
Expand All @@ -132,8 +131,7 @@ const Settings = () => {
<IonSelectOption value="fullWord">Full Word</IonSelectOption>
<IonSelectOption value="shorthand">Shorthand</IonSelectOption>
</IonSelect>
</IonItem> */}

</IonItem>

{/* APP OPTIONS */}
<IonListHeader>App Settings</IonListHeader>
Expand Down
98 changes: 98 additions & 0 deletions src/js/utils/MoveFormatter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import BaseFormatRule from "./format_rules/baseformatrule";
import CodyUSF4FormatRule from "./format_rules/codyusf4formatrule";
import DefaultFormatRule from "./format_rules/defaultformatrule";
import MenatSF5FormatRule from "./format_rules/menatsf5formatrule";
import YoungZekuSF5FormatRule from "./format_rules/youngzekusf5formatrule";

export default class MoveFormatter {
private rules: BaseFormatRule[];

constructor() {
this.rules = [
new MenatSF5FormatRule(),
new YoungZekuSF5FormatRule(),
new CodyUSF4FormatRule(),
new DefaultFormatRule()
];
}

formatToShorthand(moveData): string {
let shorthand: string;

for (const rule of this.rules) {
if (this.skipFormattingMove(moveData)) {
return "";
}

shorthand = rule.formatMove(moveData);

if (shorthand) {
return shorthand;
}
}

return "";
}

/**
* Skips character moves that meet various criteria in order to focus on applying
* formatting to normals.
* @remarks Some move types like command normals and others will sometimes get caught by the
* formatter engine because of their attributes in their JSON object.
* @param moveData The current move and its attributes as a JSON object
* @returns true if the move should not have formatting applied to it, false otherwise
*/
private skipFormattingMove(moveData): boolean {
const TARGET_COMBO: string[] = ["(TC)", "Target Combo"];
const COMMAND_NORMAL: string[] = ["3", "6"];
const SYMBOLIC_CMD_NORMAL: string[] = [">", "(air)", "(run)", "(lvl"];
const RASHID_WIND: string = "(wind)";
const IGNORED_THIRD_STRIKE_MOVES: string[] = [
"Kakushuu Rakukyaku" /* Chun-li b.MK (Hold) */,
"Inazuma Kakato Wari (Long)" /* Ken b.MK (Hold) */,
"Elbow Cannon" /* Necro db.HP */
];
const MOVE_NAME: string = moveData.moveName;

if (!moveData.numCmd) {
if (!moveData.plnCmd) {
return true;
}
}

// Do not attempt to apply formatting to target combos
if (TARGET_COMBO.some(indicator => MOVE_NAME.includes(indicator))) {
return true;
}

// Do not attempt to apply formatting to command normals
if (COMMAND_NORMAL.some(indicator => moveData.numCmd.includes(indicator))) {
return true;
}

// If the above check doesn't find anything, check for some other common indicators; if
// nothing comes back here, we're good and don't need to skip formatting
if (SYMBOLIC_CMD_NORMAL.some(indicator => moveData.plnCmd.includes(indicator))) {
return true;
}

// Rashid should be the only one (for now) to trigger this condition for his mixers
if (MOVE_NAME.includes(RASHID_WIND)) {
return true;
}

// For USF4, if the move motion is "back" but the move name doesn't include back, skip it
if (moveData.moveMotion === "B" && !MOVE_NAME.includes("Back")) {
return true;
}

// There are three awkward moves that get caught by the formatting engine
// for the 3S data. If the 3S data is ever cleaned up, this could be removed
// or refactored
if (IGNORED_THIRD_STRIKE_MOVES.some(indicator => MOVE_NAME === indicator)) {
return true;
}

return false;
}
}
101 changes: 101 additions & 0 deletions src/js/utils/format_rules/BaseFormatRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
export default abstract class BaseFormatRule {
protected characterMoveRule: string;
protected strengths: string[] = ["lp", "mp", "hp", "lk", "mk", "hk"];
protected stanceToAbbreviationMap: Map<string, string> = new Map([
["stand", "st."],
["crouch", "cr."],
["jump", "j."],
["neutral jump", "nj."],
["close", "c."],
["far", "f."],
["downback", "db."],
["back", "b."]
]);

/**
* @param rule A word, digit, or character to use as criteria for formatting
*/
constructor(rule: string) {
this.characterMoveRule = rule;
}

/**
* Given a move in its full-length form (i.e., Stand HP), returns the
* move in the common shorthand form of "abbreviated stance.abbreviated input",
* i.e. st.HP
* @param move The text representing the move as a string
* @returns A string containing the abbreviated move
*/
formatMove(moveData): string {
let formattedMoveName: string = "";

// If the move doesn't match the rule, we should break out of the method
// so the next rule can take over
if (!moveData.moveName.toLowerCase().includes(this.characterMoveRule.toLowerCase()) && this.characterMoveRule !== "") {
return formattedMoveName;
}

// If the move contains something like (Hold), use the regex format method
if (moveData.moveName.includes('(')) {
return this.formatMoveWithParenthesis(moveData.moveName);
}

let stanceAbbreviation: string = this.getStanceToAbbreviation(moveData.moveName);
let moveInput: string[] = this.extractInput(moveData);

if (moveInput.length > 1) {
formattedMoveName = `${stanceAbbreviation}${moveInput[0]} ${moveInput[1]}`;
} else {
formattedMoveName = `${stanceAbbreviation}${moveInput[0]}`;
}

return formattedMoveName;
}

/**
* Given a stance in full form (i.e., stand), returns the abbreviated version
* @param move The move provided to the call to formatMove
* @returns The stance of the move in its abbreviated form
*/
private getStanceToAbbreviation(move: string): string {
let splitMove: string[] = move.trim().toLowerCase().split(' ');
let stance: string = splitMove[0];

return this.stanceToAbbreviationMap.get(stance);
}

/**
* Given a move in its full-length form but with a trailing word
* surrounded by parenthesis (i.e., Stand HP (Hold)), returns the
* move in the common shorthand form of "abbr stance.abbr input (parenContent)"
* i.e., st.HP (Hold)
* @param move The move provided to the call to formatMove
* @returns A string containing the abbreviated move
*/
private formatMoveWithParenthesis(move: string) {
/*
Regex documentation:
Lead with \s to account for the leading space, i.e, " (Hold)", but we don't want to include it in the captured result
The outermost parentheses start the capture group of characters we DO want to capture
The character combo of \( means that we want to find an actual opening parenthesis
[a-z\s]* = Within the parenthesis, we want to find any combination of letters and spaces to account for cases like "(crouch large)"
Then we want to find the closing parenthesis with \)
The capture group is closed, and the "i" at the end sets a "case insensitive" flag for the regex expression
*/
let splitMoveFromExtraParens: string[] = move.split(/\s(\([a-z\s]*\))/i).filter((x: string) => x !== "");
let splitMove: string[] = splitMoveFromExtraParens[0].split(' ');
let modifierParens: string[] = splitMoveFromExtraParens.slice(1);
let stanceAbbreviation: string = this.stanceToAbbreviationMap.get(splitMove[0].toLowerCase());
let input: string = splitMove[splitMove.length - 1].toUpperCase();

return `${stanceAbbreviation}${input} ${modifierParens.join(' ')}`;
}

/**
* Given a move, extract the input from it. This method's logic will vary
* for some characters, but the default case simply retrieves the currently
* used input from the end of the string.
* @param move The move provided to the call to formatMove
*/
protected abstract extractInput(moveData): string[];
}
20 changes: 20 additions & 0 deletions src/js/utils/format_rules/MenatSF5FormatRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import BaseFormatRule from "./baseformatrule";

export default class MenatSF5FormatRule extends BaseFormatRule {
// Sentence-casing for the "Orb" label
private orbLabel = this.characterMoveRule.charAt(0).toUpperCase() + this.characterMoveRule.slice(1);

constructor() {
super("orb");
}

protected extractInput(moveData): string[] {
let input: string[] = [];
let moveInput: string = moveData.moveName.split(' ').find(x => this.strengths.some(y => y === x.toLowerCase()));

input.push(moveInput.toUpperCase());
input.push(this.orbLabel);

return input;
}
}
19 changes: 19 additions & 0 deletions src/js/utils/format_rules/YoungZekuSF5FormatRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import BaseFormatRule from "./baseformatrule";

export default class YoungZekuSF5FormatRule extends BaseFormatRule {
constructor() {
super("late");
}

protected extractInput(moveData): string[] {
let input: string[] = [];
let splitMove = moveData.moveName.toLowerCase().split(' ');
let lateHit: string = `${splitMove[2]} ${splitMove[3]}`;

input.push(splitMove[1].toUpperCase())
input.push(lateHit);

return input;
}

}
21 changes: 21 additions & 0 deletions src/js/utils/format_rules/codyusf4formatrule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import BaseFormatRule from "./baseformatrule";

export default class CodyUSF4FormatRule extends BaseFormatRule {
// Sentence-casing for the "Knife" label
private knifeLabel: string = this.characterMoveRule.charAt(0).toUpperCase() + this.characterMoveRule.slice(1);

constructor() {
super("knife");
}

protected extractInput(moveData): string[] {
let input: string[] = [];
let moveInput: string = moveData.moveName.split(' ').find(x => this.strengths.some(y => y === x.toLowerCase()));

input.push(moveInput.toUpperCase());
input.push(this.knifeLabel);

return input;
}

}
17 changes: 17 additions & 0 deletions src/js/utils/format_rules/defaultformatrule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import BaseFormatRule from "./baseformatrule";

export default class DefaultFormatRule extends BaseFormatRule {
constructor() {
super("");
}

protected extractInput(moveData): string[] {
let input: string[] = [];
let splitMove = moveData.moveName.trim().split(' ');

input.push(splitMove[splitMove.length - 1].toUpperCase());

return input;
}

}
Loading