Skip to content

Commit 63d365f

Browse files
committed
added 'IsDFA' feature
1 parent 95bbee1 commit 63d365f

File tree

7 files changed

+263
-15
lines changed

7 files changed

+263
-15
lines changed

src/components/Editor.tsx

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createContext, useState } from "react";
2-
import { Box, Grid } from "@mui/material";
2+
import { Box, Button, Grid } from "@mui/material";
33
import { GridColumns, GridActionsCellItem } from "@mui/x-data-grid";
44
import DeleteIcon from "@mui/icons-material/Delete";
55
import SaveSharpIcon from "@mui/icons-material/SaveSharp";
@@ -17,6 +17,8 @@ import { PlaygroundSize } from "./types/PlaygroundSize";
1717
import { StyledTransitionLabel } from "../features/components/playground/StyledTransitionLabel";
1818
import { MaxNumberOfStates } from "../consts/MaxNumberOfStates";
1919
import { AutomataData } from "./types/AutomataData";
20+
import { Tools } from "./Tools";
21+
import { ToolsProps } from "./props/ToolsProps";
2022

2123
export const DataContext = createContext<AutomataData>({} as AutomataData);
2224

@@ -546,6 +548,10 @@ export const Editor = () => {
546548
setSize,
547549
};
548550

551+
const toolsProps: ToolsProps = {
552+
rows,
553+
};
554+
549555
return (
550556
<DataContext.Provider
551557
value={{
@@ -561,7 +567,7 @@ export const Editor = () => {
561567
>
562568
<>
563569
<Box sx={{ flexGrow: 1, m: 1 }}>
564-
{/* Grid to incorporate Transition table and Automata */}
570+
{/* Grid to incorporate Transition table and Playground */}
565571
<Grid
566572
container
567573
columnSpacing={{
@@ -572,14 +578,38 @@ export const Editor = () => {
572578
>
573579
{/* Transition table grid */}
574580
<Grid item xs={12} md={4}>
581+
{/* Grid for Add a Row button and Tools */}
582+
<Grid container alignItems={"center"}>
583+
<Grid item xs={10}>
584+
<Button
585+
size="small"
586+
onClick={() =>
587+
handleAddRow(
588+
new RowModel(
589+
rowId,
590+
`q${rowId}`,
591+
"",
592+
"",
593+
"",
594+
false,
595+
false
596+
)
597+
)
598+
}
599+
>
600+
Add a row
601+
</Button>
602+
</Grid>
603+
604+
<Grid item xs={2}>
605+
<Tools {...toolsProps} />
606+
</Grid>
607+
</Grid>
575608
<TransitionTable {...transitionTableProps} />
576609
</Grid>
577-
{/* Automata grid */}
578-
<Grid container item xs={12} md={8}>
579-
{/* Automata canvas grid */}
580-
<Grid item xs={12}>
581-
<Playground {...playgroundProps} />
582-
</Grid>
610+
{/* Playground grid */}
611+
<Grid item xs={12} md={8}>
612+
<Playground {...playgroundProps} />
583613
</Grid>
584614
</Grid>
585615
</Box>

src/components/Tools.tsx

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import {
2+
Box,
3+
Tooltip,
4+
IconButton,
5+
Menu,
6+
Typography,
7+
Divider,
8+
List,
9+
ListItem,
10+
ListItemButton,
11+
ListItemIcon,
12+
ListItemText,
13+
Button,
14+
Drawer,
15+
Toolbar,
16+
MenuItem,
17+
} from "@mui/material";
18+
import { useState } from "react";
19+
import MoreIcon from "@mui/icons-material/MoreVert";
20+
import { Download } from "../features/Download";
21+
import { Upload } from "../features/Upload";
22+
import InboxIcon from "@mui/icons-material/MoveToInbox";
23+
import MailIcon from "@mui/icons-material/Mail";
24+
import { ToolsProps } from "./props/ToolsProps";
25+
import { IsDFA } from "../utils/IsDFA";
26+
27+
export const Tools = (props: ToolsProps) => {
28+
console.log("re rendering Tools: props");
29+
30+
const [anchorElUser, setAnchorElUser] = useState<null | HTMLElement>(null);
31+
32+
const handleOpenUserMenu = (event: React.MouseEvent<HTMLElement>) => {
33+
setAnchorElUser(event.currentTarget);
34+
};
35+
36+
const handleCloseToolsMenu = () => {
37+
setAnchorElUser(null);
38+
};
39+
40+
// const [isDrawerOpen, setIsDrawerOpen] = useState(false);
41+
42+
// const toggleDrawer =
43+
// (open: boolean) => (event: React.KeyboardEvent | React.MouseEvent) => {
44+
// if (
45+
// event.type === "keydown" &&
46+
// ((event as React.KeyboardEvent).key === "Tab" ||
47+
// (event as React.KeyboardEvent).key === "Shift")
48+
// ) {
49+
// return;
50+
// }
51+
52+
// setIsDrawerOpen(open);
53+
// };
54+
55+
// const list = () => (
56+
// <Box
57+
// sx={{ width: 250 }}
58+
// role="presentation"
59+
// onClick={toggleDrawer(false)}
60+
// onKeyDown={toggleDrawer(false)}
61+
// >
62+
// <List>
63+
// {["Inbox", "Starred", "Send email", "Drafts"].map((text, index) => (
64+
// <ListItem key={text} disablePadding>
65+
// <ListItemButton>
66+
// <ListItemIcon>
67+
// {index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
68+
// </ListItemIcon>
69+
// <ListItemText primary={text} />
70+
// </ListItemButton>
71+
// </ListItem>
72+
// ))}
73+
// </List>
74+
// <Divider />
75+
// <List>
76+
// {["All mail", "Trash", "Spam"].map((text, index) => (
77+
// <ListItem key={text} disablePadding>
78+
// <ListItemButton>
79+
// <ListItemIcon>
80+
// {index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
81+
// </ListItemIcon>
82+
// <ListItemText primary={text} />
83+
// </ListItemButton>
84+
// </ListItem>
85+
// ))}
86+
// </List>
87+
// </Box>
88+
// );
89+
90+
return (
91+
// <>
92+
// <Button onClick={toggleDrawer(true)}>Tools</Button>
93+
// <Drawer
94+
// anchor="left"
95+
// open={isDrawerOpen}
96+
// onClose={toggleDrawer(false)}
97+
// sx={{
98+
// width: 250,
99+
// flexShrink: 0,
100+
// [`& .MuiDrawer-paper`]: {
101+
// width: 250,
102+
// boxSizing: "border-box",
103+
// },
104+
// }}
105+
// >
106+
// {list()}
107+
// </Drawer>
108+
// </>
109+
110+
<Box>
111+
<Button
112+
size="small"
113+
aria-label="tools"
114+
aria-controls="menu-appbar-tools"
115+
aria-haspopup="true"
116+
onClick={handleOpenUserMenu}
117+
sx={{ marginLeft: 3 }}
118+
>
119+
Tools
120+
</Button>
121+
<Menu
122+
id="menu-appbar-tools"
123+
anchorEl={anchorElUser}
124+
anchorOrigin={{
125+
vertical: "bottom",
126+
horizontal: "left",
127+
}}
128+
keepMounted
129+
transformOrigin={{
130+
vertical: "top",
131+
horizontal: "left",
132+
}}
133+
open={Boolean(anchorElUser)}
134+
onClose={handleCloseToolsMenu}
135+
>
136+
<Download handleCloseToolsMenu={handleCloseToolsMenu} />
137+
<Upload handleCloseToolsMenu={handleCloseToolsMenu} />
138+
<MenuItem
139+
onClick={() => {
140+
handleCloseToolsMenu();
141+
IsDFA(props.rows);
142+
}}
143+
>
144+
<Button variant="text" component="label">
145+
Is DFA
146+
</Button>
147+
</MenuItem>
148+
</Menu>
149+
</Box>
150+
);
151+
};

src/components/props/ToolsProps.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { RowModel } from "../../models";
2+
3+
export type ToolsProps = {
4+
rows: RowModel[];
5+
};

src/enums/pages.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
export enum Pages {
22
Editor = "Editor",
3-
NFA_TO_DFA = "NFA to DFA",
4-
MIN_DFA = "Minimize DFA",
5-
TEST_STRING = "Test a String",
6-
Is_DFA = "Is DFA",
7-
Is_NFA = "Is NFA",
3+
// NFA_TO_DFA = "NFA to DFA",
4+
// MIN_DFA = "Minimize DFA",
5+
// TEST_STRING = "Test a String",
6+
// Is_DFA = "Is DFA",
87
Help = "Help",
98
About = "About",
109
}

src/features/TransitionTable.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const TransitionTable = (props: TransitionTableProps) => {
2727

2828
return (
2929
<>
30-
<Grid container alignItems={"center"}>
30+
{/* <Grid container alignItems={"center"}>
3131
<Grid item xs={11}>
3232
<Button
3333
size="small"
@@ -83,7 +83,7 @@ const TransitionTable = (props: TransitionTableProps) => {
8383
</Menu>
8484
</Box>
8585
</Grid>
86-
</Grid>
86+
</Grid> */}
8787

8888
<Box
8989
sx={{

src/features/Upload.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const Upload = ({
2525
};
2626

2727
const handleFileChange = (event: any) => {
28+
event.preventDefault();
2829
console.log("handleFileChange");
2930
if (event?.target?.files?.length > 0) {
3031
const newFile: File = event?.target?.files[0];
@@ -61,6 +62,7 @@ export const Upload = ({
6162
console.log("Successfuly uploaded data.");
6263
};
6364
reader.readAsText(newFile);
65+
//clear file input (cache)
6466
event.target.value = "";
6567
}
6668
handleCloseToolsMenu();

src/utils/IsDFA.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { PossibleTransitionValues } from "../consts/PossibleTransitionValues";
2+
import { RowModel } from "../models";
3+
4+
export const IsDFA = (rows: RowModel[]) => {
5+
let missingTransitions = new Set<string>();
6+
let nullTransitions = new Set<string>();
7+
let multiPathTransitions = new Set<string>();
8+
const numberOfInitialStates = rows.filter((row) => row.isInitial).length;
9+
const numberOfFinalStates = rows.filter((row) => row.isFinal).length;
10+
11+
rows.forEach((row) => {
12+
PossibleTransitionValues.forEach((key) => {
13+
let transitionValue = row[key === "^" ? "nul" : key]
14+
.toString()
15+
.split(" ")
16+
.filter((v) => v !== "");
17+
if (key === "^" && transitionValue.length > 0) {
18+
nullTransitions.add(row.state);
19+
} else if (key !== "^" && transitionValue.length === 0) {
20+
missingTransitions.add(row.state);
21+
}
22+
if (transitionValue.length > 1) {
23+
multiPathTransitions.add(row.state);
24+
}
25+
});
26+
});
27+
28+
let alertMessage = "";
29+
if (numberOfInitialStates === 0) {
30+
alertMessage += "There is no initial state.\n";
31+
}
32+
33+
if (numberOfInitialStates === 1 && numberOfFinalStates === 0) {
34+
alertMessage += "There is/are no final state(s).\n";
35+
}
36+
if (numberOfInitialStates === 1 && numberOfFinalStates > 0) {
37+
const arrayOfMissingTransitions = Array.from(missingTransitions);
38+
const arrayOfNullTransitions = Array.from(nullTransitions);
39+
const arrayOfMultiPathTransitions = Array.from(multiPathTransitions);
40+
41+
if (arrayOfMissingTransitions.length > 0) {
42+
alertMessage +=
43+
"There are missing transitions on state(s): " +
44+
arrayOfMissingTransitions.join(", ") +
45+
".\n";
46+
}
47+
if (arrayOfNullTransitions.length > 0) {
48+
alertMessage +=
49+
"There are null transitions on state(s): " +
50+
arrayOfNullTransitions.join(", ") +
51+
".\n";
52+
}
53+
if (arrayOfMultiPathTransitions.length > 0) {
54+
alertMessage +=
55+
"There are multi-path transitions on state(s): " +
56+
arrayOfMultiPathTransitions.join(", ") +
57+
".\n";
58+
}
59+
}
60+
alert(alertMessage !== "" ? alertMessage : "The automaton is a DFA.");
61+
};

0 commit comments

Comments
 (0)