Skip to content

initial commit #22

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
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
14,796 changes: 14,796 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions src/components/fibonacci-page/fibonacci-page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.container {
display: flex;
width: 55%;
gap: 12px;
margin: 0 auto;
justify-content: center;
}


.letterContainer {
display: flex;
width: 80%;
gap: 16px;
margin: 100px auto;
justify-content: center;
flex-wrap: wrap;
row-gap: 100px;
}
62 changes: 60 additions & 2 deletions src/components/fibonacci-page/fibonacci-page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,68 @@
import React from "react";
import React, { useState, useEffect } from "react";
import styles from './fibonacci-page.module.css';
import { SolutionLayout } from "../ui/solution-layout/solution-layout";
import { Input } from "../ui/input/input";
import { Button } from "../ui/button/button";
import { Circle } from "../ui/circle/circle";
import { getFibonacciNumbers } from "./util";


export const FibonacciPage: React.FC = () => {
const [index, setIndex] = useState<number>(0);
const [number, setNumber] = useState<string>('');
const [isValid, setIsValid] = useState(false);
const [isButtonPressed, setIsButtonPressed] = useState(false);
const [isLoader, setIsLoader] = useState<boolean>(false);
useEffect(() => {
setIsValid(+number < 20 && +number > 0);
const interval = setInterval(() => {
if (isButtonPressed && (index < (getFibonacciNumbers(+number).length - 1))) {
setIndex(prev => prev + 1);
setIsLoader(true)
}
}, 500);
if (index === (getFibonacciNumbers(+number).length - 1)) {
setIsLoader(false)
}

return () => { clearInterval(interval); }

}, [isButtonPressed, index, number])

const handleInput = (evt: React.FormEvent<HTMLInputElement>) => {
const target = evt.target as HTMLInputElement;
setNumber(target.value)

}

return (
<SolutionLayout title="Последовательность Фибоначчи">

<div className={styles.container}>
<Input max={19} type={"number"} isLimitText={true} onChange={(evt) => handleInput(evt) } />
< Button text={'Развернуть'} isLoader={isLoader ? true : false} disabled = {!isValid} onClick={() => {
setIsButtonPressed(true)
}} />
</div>
<div className={styles.letterContainer}>
{isValid && isButtonPressed && < CircleComponent number={getFibonacciNumbers(+number)[index]} />}
</div>
</SolutionLayout>
);
};

type CircleComponentProps = {
number: number[];
}

const CircleComponent = ({ number }: CircleComponentProps) => {
return (
<>
{number.map((item, index) => {
if (item !== 0) {
return <Circle letter={item.toString()} tail={(index - 1).toString()} key={index} />
}
})}
</>

)
}
11 changes: 11 additions & 0 deletions src/components/fibonacci-page/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const getFibonacciNumbers = (number: number) => {
const array: number[][] = []
let arr: number[] = [0, 1];
for (let i = 2; i <= number; i++) {
arr.push(arr[i - 2] + arr[i - 1])
array.push([...arr])
}
array.unshift([0,1])
return array;

}
19 changes: 19 additions & 0 deletions src/components/list-page/list-page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.container {
display: flex;
gap: 10px;
}

.letterContainer {
display: flex;
width: 80%;
gap: 16px;
margin: 100px auto;
justify-content: center;
flex-wrap: wrap;
row-gap: 100px;
}

.circleContainer {
display: flex;
align-items: center;
}
200 changes: 198 additions & 2 deletions src/components/list-page/list-page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,206 @@
import React from "react";
import React, { useEffect, useState } from "react";
import styles from "./list-page.module.css";
import { SolutionLayout } from "../ui/solution-layout/solution-layout";
import { Input } from "../ui/input/input";
import { Button } from "../ui/button/button";
import { ElementStates } from "../../types/element-states";
import { Circle } from "../ui/circle/circle";
import { ArrowIcon } from "../ui/icons/arrow-icon"
import { NodeList } from "./utils";


export const ListPage: React.FC = () => {
const [string, setString] = useState<string>('');
const [flag, setFlag] = useState(false);
const [list, setList] = useState<string[]>(['0', '34', '8', '1']);
const li = new NodeList(list);
const [index, setIndex] = useState<number | string>('')
const [yetAnIndex, setYetAnIndex] = useState<number>(-1) // это индекс для счетчика в useEffect
const [flagForHead, setFlagForHead] = useState<string>('')
const [flagForTail, setFlagForTail] = useState<string>('')
const [flagForGreen, setFlagForGreen] = useState(false)
const [circleContent, setCircleContent] = useState('')
const [count, setCount] = useState<number>(-1)
const [yetAnCount, setYetAnCount] = useState<number | string>('-1')
const [anotherCount, setAnotherCount] = useState<number>(-1)// это счетчик для удаления по индексу
const [isLoader, setIsLoader] = useState<boolean>(false);

useEffect(() => {
const interval = setInterval(() => {
if (yetAnIndex > -1 && anotherCount < yetAnIndex) {
setAnotherCount(prev => prev + 1);
}
}, 1000);
return () => {
clearInterval(interval);
}
}, [anotherCount])

const inHead = () => {
setFlagForHead(string)
setCount(0)
setYetAnCount('0')
setString('')
li.prepend(string)
setTimeout(() => {
setFlagForHead('')
}, 1000)
setTimeout(() => {
setCount(-1)
setYetAnCount('-1')
}, 2000)
setTimeout(() => {
setList(li.toArray())
}, 1000)
}

const inTail = () => {
setFlagForHead(string)
setCount(list.length - 1)
setYetAnCount(list.length)
setString('')
setIndex('')
li.append(string)
setTimeout(() => {
setFlagForHead('')
}, 1000)
setTimeout(() => {
setCount(-1)
setYetAnCount('-1')
}, 2000)
setTimeout(() => {
setList([...li.toArray()])
}, 1000)
}

const fromHead = () => {
setCount(0)
setFlagForTail(list[0]);
setCircleContent(list[0])
list[0] = '';
setList([...list]);
li.shift();
setTimeout(() => {
setString('')
setCount(-1)
setList([...li.toArray()])
setFlagForTail('');
setCircleContent('')
}, 1000);

}

const fromTail = () => {
setCount(list.length - 1)
setFlagForTail(list[list.length - 1]);
setCircleContent(list[list.length - 1])
list[list.length - 1] = '';
setList([...list]);
li.pop();
setTimeout(() => {
setString('')
setCount(-1)
setList([...li.toArray()])
}, 1000);

}

const insertByIndex = () => {
setAnotherCount(0)
setFlagForHead(list[yetAnIndex]);
setFlag(true)
li.insert(index, string)
setString('')
setIndex('')
setTimeout(() => {
setYetAnIndex(-1)
}, 1000 * yetAnIndex);
setTimeout(() => {
setList([...li.toArray()])
setFlagForHead('');
setFlagForGreen(true)
}, 1000 * yetAnIndex + 1000);
setTimeout(() => {
setFlag(false)
setAnotherCount(-1)
setFlagForGreen(false)
}, 1000 * yetAnIndex + 2000)
}

const removeByIndex = () => {
setString('')
setAnotherCount(0)
setFlag(true)
li.removeByIndex(index)
setIndex('')
setTimeout(() => {
setFlagForTail(list[yetAnIndex]);
setCircleContent(list[yetAnIndex])
list[yetAnIndex] = '';
setList([...list]);
setYetAnIndex(-1)
}, 1000 * yetAnIndex + 1000);

setTimeout(() => {
setFlag(false)
setList([...li.toArray()])
setAnotherCount(-1)

setFlagForTail('');
}, 1000 * yetAnIndex + 2000);
}

return (
<SolutionLayout title="Связный список">

<div className={styles.container} >
<Input maxLength={4} isLimitText={true} name={"MyInput"} type={'text'} value={string} onChange={(evt: any) => {
setString(evt.target.value)
setCircleContent(evt.target.value)
}} />
<Button text={"Добавить в head"} isLoader={isLoader ? true : false} type={"button"} disabled={!string} onClick={inHead} />
<Button text={"Добавить в tail"} type={"button"} disabled={!string} onClick={inTail} />
<Button text={"Удалить из head"} type={"button"} disabled={list.length > 0 ? false : true} onClick={fromHead} />
<Button text={"Удалить из tail"} type={"button"} disabled={list.length > 0 ? false : true} onClick={fromTail} />
</div>
<div className={styles.container}>
<Input name={"MyIndex"} type={'text'} value={index} onChange={(evt: any) => {
setIndex(evt.target.value)
setYetAnIndex(evt.target.value)
}} />
<Button text={"Добавить по индексу"} type={"button"} disabled={!string} onClick={insertByIndex} />
<Button text={"Удалить по индексу"} type={"button"} disabled={!index} onClick={removeByIndex} />
</div>
<div className={styles.letterContainer}>
<CircleComponent array={[...list]} string={circleContent} count={count} yetAnCount={yetAnCount} flagForHead={flagForHead} flagForTail={flagForTail} flag={flag} flagForGreen={flagForGreen} anotherCount={anotherCount} />
</div>
</SolutionLayout>
);
};

type CircleComponentProps = {
array: string[];
string: string;
count: string | number;
flagForHead: string;
flag: boolean;
yetAnCount: string | number;
anotherCount: number
flagForTail: string;
flagForGreen: boolean;
}

const CircleComponent = ({ array, string, count, yetAnCount, flagForHead, flag, flagForTail,flagForGreen, anotherCount }: CircleComponentProps) => {
return (
<>
{!flag && array && array.map((item, index) => {
return <div className={styles.circleContainer}> <Circle letter={item.toString()} head={flagForHead && index === +count ? <Circle isSmall={true} letter={string} state={ElementStates.Changing} /> : index === 0 ? 'top' : null} tail={flagForTail && index === +count ? <Circle isSmall={true} letter={string} state={ElementStates.Changing} /> : index === array.length - 1 ? 'tail' : null} key={index} index={index}
state={flagForHead === '' && index === +yetAnCount ? ElementStates.Modified : ElementStates.Default} /> {index < array.length - 1 ? <ArrowIcon /> : null}</div>
})}
{flag && array && array.map((item, index) => {
return <div className={styles.circleContainer}> <Circle letter={item.toString()} head={flagForHead && index === anotherCount ? <Circle isSmall={true} letter={string} state={ElementStates.Changing} /> : index === 0 ? 'top' : null} tail={flagForTail && index === anotherCount ? <Circle isSmall={true} letter={string} state={ElementStates.Changing} /> : index === array.length - 1 ? 'tail' : null} key={index} index={index}
state={!flagForGreen && index <= anotherCount ? ElementStates.Changing : (index === anotherCount) ? ElementStates.Modified : ElementStates.Default} /> {index < array.length - 1 ? <ArrowIcon /> : null}</div>
})}
</>

)
}
158 changes: 158 additions & 0 deletions src/components/list-page/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
type TNode = {
value: string;
next: TNode | null
}
class Node implements TNode {
value: string;
next: TNode | null
constructor(value: string, next?: TNode | null) {
this.value = value;
this.next = (next === undefined ? null : next);
}
}

type TNodeList = {
head: TNode | null;
tail: TNode | null;
length: number;
}


export class NodeList implements TNodeList {
public head: TNode | null;
public tail: TNode | null;
public length: number;
constructor(elements: string[]) {
this.head = null;
this.tail = null;
this.length = 0;
if (elements) {
elements.forEach((el) => {
this.append(el);
this.length = elements.length;
});
}
}

public toArray() {
const nodes = [];
let currentNode: TNode | null = this.head;
// Перебираем все узлы и добавляем в массив.
while (currentNode) {
nodes.push(currentNode.value);
currentNode = currentNode.next;
}
// Возвращаем массив из всех узлов.
return nodes;
}

public prepend(value: string) {
let node = new Node(value);
node.next = this.head;
this.head = node;
this.length++;
return this
}

public append(value: string) {
const node = new Node(value);
if (!this.head || !this.tail) {
this.head = node;
this.tail = node;
return this
}
this.tail.next = node;
this.tail = node;
this.length++;
return this;

}

public shift() {
let currentNode: TNode | null = this.head;
if (currentNode && currentNode.next !== null) {
this.head = currentNode.next;
} else {
this.head = null
}
this.length--;

return this
}

public pop() {
let currentNode: TNode | null = this.head;
// если узел единственный и отстутвует ссылка на следующий узел то равняем head с нулем
if (currentNode && currentNode.next === null) {
this.head = null
}
while (currentNode && currentNode.next) {
// Если у следующего узла нет следующего узла, значит текущий узел предпоследний.
if (!currentNode.next.next) {
// убираем ссылку «next» на последний узел.
currentNode.next = null;
} else {
// Перематываем на один узел вперед.
currentNode = currentNode.next;
}
}
}

public removeByIndex(index: number | string) {
index = +index;
if ((index && index < 0) || (index && index > this.length)) {
return 'Enter a valid index';
}

let current: TNode | null = this.head;

if (current && index === 0) {
this.head = current.next;
} else {
let prev = null;
let count = 0;

while (current && count < index) {
prev = current;
current = current.next;
count++;
}
if (current && prev) {
prev.next = current.next;
}
}

this.length--;
return this;
}

public insert(index: number | string, value: string) {
index = +index
if ((index && index < 0) || (index && index > this.length)) {
console.log('Введите правильный индекс');
return;
} else if (index === this.length) {
return this.append(value);
} else {
const node = new Node(value);
if (index === 0) {
node.next = this.head;
this.head = node;

} else {
let curr = this.head;
let currIndex = 0;
while (curr && currIndex !== index - 1) {
curr = curr.next
currIndex++
}

if (curr && curr.next) {
node.next = curr.next
curr.next = node
}
}
this.length++;
}
}
}
14 changes: 14 additions & 0 deletions src/components/queue-page/queue-page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.container {
display: flex;
gap: 10px;
}

.letterContainer {
display: flex;
width: 80%;
gap: 16px;
margin: 100px auto;
justify-content: center;
flex-wrap: wrap;
row-gap: 100px;
}
104 changes: 102 additions & 2 deletions src/components/queue-page/queue-page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,110 @@
import React from "react";
import React, { useState, useEffect } from "react";
import styles from "./queue-page.module.css";
import { SolutionLayout } from "../ui/solution-layout/solution-layout";
import { Input } from "../ui/input/input";
import { Button } from "../ui/button/button";
import { Circle } from "../ui/circle/circle";
import { ElementStates } from "../../types/element-states";
import { Queue } from "./utils";

export const QueuePage: React.FC = () => {
const [string, setString] = useState<string>('');
const [flag, setFlag] = useState(true);
const [colorState, setColorState] = useState<number>(-1);
const [queue, setQueue] = useState<string[]>(['', '', '', '', '', '', '',]);
const [head, setHead] = useState<number>(-1);
const [tail, setTail] = useState(-1);
const qu = new Queue(queue);
useEffect(() => {
setFlag(true)
queue.forEach((item) => {
if (item !== '') {
setFlag(false)
}
})
const interval = setInterval(() => {
setColorState(-1);
}, 1000);
return () => {
clearInterval(interval);
}
}, [queue, colorState])

const handlePush = (e: any) => {
e.preventDefault();
// Read the form data
const form = e.target;
const formData = new FormData(form);
// Or you can work with it as a plain object:
const formJson = Object.fromEntries(formData.entries());
const string: any = formJson.MyInput
setString('')
setColorState(tail + 1)
setTimeout(() => {
qu.enqueue(string, tail + 1)
qu.head()
qu.tail()
setTail(qu.tail())
setHead(qu.head())
setQueue([...queue])
}, 1000)
}

const handlePop = () => {
setColorState(head)
setTimeout(() => {
qu.dequeue()
qu.head()
qu.tail()
setTail(qu.tail())
setHead(qu.head())
setQueue([...queue])
}, 1000);
}

const handleClear = () => {
qu.clear()
setQueue(['', '', '', '', '', '', '',])
setTail(-1)
setHead(-1)
}

return (
<SolutionLayout title="Очередь">

<form className={styles.container} onSubmit={handlePush} >
<Input maxLength={4} isLimitText={true} name={"MyInput"} type={'text'} value={string} onChange={(evt: any) => {
setString(evt.target.value)
}} />
<Button text={"Добавить"} type={"submit"} disabled={!string} />
<Button text={"Удалить"} type={"button"} disabled={flag ? true : false} onClick={() => handlePop()} />
<Button text={"Очистить"} type={"button"} disabled={flag ? true : false} onClick={() => handleClear()} />
</form>
<div className={styles.letterContainer}>
<CircleComponent array={[...queue]} colorState={colorState} head={head} tail={tail} />
</div>
</SolutionLayout>
);
};

type CircleComponentProps = {
array: string[];
colorState: number;
head: number;
tail: number | undefined;
}

const CircleComponent = ({ array, colorState, head, tail }: CircleComponentProps) => {
const [flag, setFlag] = useState<number>(0);
useEffect(() => {
setFlag(colorState)
}, [colorState])
return (
<>
{array && array.map((item, index) => {
return <Circle letter={item.toString()} head={index === head ? "top" : null} tail={index === tail ? "tail" : null} key={index}
state={index === flag ? ElementStates.Changing : ElementStates.Default} />
})}
</>

)
}
57 changes: 57 additions & 0 deletions src/components/queue-page/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

type TQueue<T> = {
enqueue: (item: T, tail: number) => void;
dequeue: () => T[] | string[];
elements: () => T[] | string[];
isEmpty: () => boolean;
clear: () => T[] | string[];
head: () => number;
tail: () => number;
}
export class Queue<T> implements TQueue<T> {
private items: T[] | string[] = [];
constructor(queue: T[]) {
this.items = queue;
}

enqueue (item: T, tail: number): void {
if (tail <= 0) {
let index = this.items.findIndex(item => item === '')
this.items[index] = item;
}
else {
this.items[tail] = item
}
}

dequeue() {
if (this.isEmpty()) {
throw new Error("No elements in the queue");
}
let index = this.items.findIndex(item => item !== '')
this.items[index] = '';
return this.items;
}

isEmpty() {
return this.items.length === 0;
}
elements() {
return this.items;
}
clear() {
return this.items = ['', '', '', '', '', '', '',];
}
head() {
return this.items.findIndex(item => item !== '');
}
tail() {
let index: number = -1;
for (let i = this.items.length - 1; i >= 0; i--) {
if (this.items[i] !== '') {
return index = i;
}
}
return index;
}
}
25 changes: 25 additions & 0 deletions src/components/sorting-page/sorting-page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.buttonsContainer {
display: flex;
justify-content: space-between;
width: 80%;
margin: 0 auto;
align-items: center;
}

.radioButtonsWrapper {
display: flex;
gap: 40px;
}

.buttonsWrapper {
display: flex;
gap: 12px;
}

.columnWrapper {
display: flex;
gap: 10px;
margin: 48px auto 0;
justify-content: center;
align-items: flex-end;
}
104 changes: 102 additions & 2 deletions src/components/sorting-page/sorting-page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,110 @@
import React from "react";
import React, { useState, useEffect } from "react";
import styles from "./sorting-page.module.css";
import { SolutionLayout } from "../ui/solution-layout/solution-layout";
import { Column } from "../ui/column/column";
import { RadioInput } from "../ui/radio-input/radio-input";
import { Button } from "../ui/button/button";
import { Direction } from "../../types/direction";
import { ElementStates } from "../../types/element-states";
import { choiceSortAscending, choiceSortDescending, bubleSortAscending, bubleSortDescending } from "./utils";

export const SortingPage: React.FC = () => {
const [choiceSort, setChoiceSort] = useState(true)
const [steps, setSteps] = useState<[number[], number, number, number][]>();
const [arr, setArr] = useState<number[]>();
const [index, setIndex] = useState<number>(0);
const [isLoaderAsc, setIsLoaderAsc] = useState(false);
const [isLoaderDesc, setIsLoaderDesc] = useState(false);
const [isButtonPressed, setIsButtonPressed] = useState(false);
const [flag, setFlag] = useState(false);

const randomArr = () => {
const arrLength = Math.floor(Math.random() * 15) + 3;
const randomArray = Array.from({ length: arrLength }, () => Math.floor(Math.random() * 101));
if (arr) {
return [...randomArray]
} else {
return randomArray
}
}
useEffect(() => {
const interval = setInterval(() => {
if (isButtonPressed && steps && (index < (steps.length - 1))) {
setIndex(prev => prev + 1);
}
}, 1000);
if (steps && index === (steps.length - 1)) {
setIsLoaderAsc(false)
setIsLoaderDesc(false)
}

return () => { clearInterval(interval); }

}, [isButtonPressed, index])

const startBubleSortAscAlgoritm = (arr: number[]) => {
setSteps(bubleSortAscending(arr));
setFlag(true)
}
const startBubleSortDescAlgoritm = (arr: number[]) => {
setSteps(bubleSortDescending(arr));
setFlag(true)
}

return (
<SolutionLayout title="Сортировка массива">

<>
<div className={styles.buttonsContainer}>
<div className={styles.radioButtonsWrapper}>
<RadioInput label={"Выбор"} name={'method'} defaultChecked={true} value={'choice'} onClick={() => setChoiceSort(true)} />
<RadioInput label={"Пузырёк"} name={'method'} value={'buble'} onClick={() => setChoiceSort(false)} />
</div>
<div className={styles.buttonsWrapper}>
<Button sorting={Direction.Ascending} text={"По возрастанию"} isLoader={isLoaderAsc ? true : false} onClick={() => {
if (arr) {
choiceSort ? setSteps(choiceSortAscending(arr)) : startBubleSortAscAlgoritm(arr)
setIsLoaderAsc(true);
setIsButtonPressed(true);
setArr(undefined)
}
}} />
<Button sorting={Direction.Descending} text={"По убыванию"} isLoader={isLoaderDesc ? true : false} onClick={() => {
if (arr) {
choiceSort ? setSteps(choiceSortDescending(arr)) : startBubleSortDescAlgoritm(arr)
setIsLoaderDesc(true);
setIsButtonPressed(true);
setArr(undefined)
}
}} />
</div>
<Button text={"Новый массив"} onClick={() => {
setArr(randomArr)
setSteps(undefined)
setIndex(0)
setIsButtonPressed(false);
}} />
</div>
<div className={styles.columnWrapper}>
{steps ? <ColumnsComponent flag={flag} array={[...steps[index]]} /> : arr && <ColumnsComponent arr={[...arr]} flag={flag} />}
</div>
</>
</SolutionLayout>
);
};

type ColumnsComponentProps = {
array?: [number[], number, number, number];
arr?: number[];
flag: boolean;
}


const ColumnsComponent = ({ array, arr, flag }: ColumnsComponentProps) => {
return (
<>
{!flag && array && array[0].map((item, index) => <Column index={item} key={index} state={(index === array[1] || index === array[2]) ? ElementStates.Changing : (index < array[3]) ? ElementStates.Modified : ElementStates.Default} />)}
{flag && array && array[0].map((item, index) => <Column index={item} key={index} state={(index === array[1] || index === array[2]) ? ElementStates.Changing : (index > array[3]) ? ElementStates.Modified : ElementStates.Default} />)}
{arr && arr.map((item, index) => <Column index={item} key={index} />)}
</>
)
}
91 changes: 91 additions & 0 deletions src/components/sorting-page/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
const swap = (arr: number[], firstIndex: number, secondIndex: number): void => {
const temp = arr[firstIndex];
arr[firstIndex] = arr[secondIndex];
arr[secondIndex] = temp;
};

export const choiceSortAscending = (initialArray: number[]) => {
const array = [...initialArray]
const { length } = array;
let counter = 0;
const steps: [number[], number, number, number][] = [];
for (let i = 0; i < length - 1; i++) {
let minInd = i;
for (let j = i + 1; j < length; j++) {
steps.push([[...array], minInd, j, counter]);
if (array[j] < array[minInd]) {
minInd = j;
}
}
if (minInd === i) {
counter++
}
if (minInd !== i) {
counter++
swap(array, i, minInd)
}
}
steps.push([[...array], -1, -1, length]);
return steps
}

export const choiceSortDescending = (initialArray: number[]) => {
const array = [...initialArray]
const { length } = array;
let counter = 0;
const steps: [number[], number, number, number][] = [];
for (let i = 0; i < length - 1; i++) {
let minInd = i;
for (let j = i + 1; j < length; j++) {
steps.push([[...array], minInd, j, counter]);
if (array[j] > array[minInd]) {
minInd = j;
}
}
if (minInd === i) {
counter++
}
if (minInd !== i) {
counter++
swap(array, i, minInd)
}
}
steps.push([[...array], -1, -1, length]);
return steps
}

export const bubleSortAscending = (initialArray: number[]) => {
const steps: [number[], number, number, number][] = [];
const array = [...initialArray]
const { length } = array;
let counter = length;
for (let i = 0; i < length; i++) {
counter = counter - 1;
for (let j = 0; j < length - i - 1; j++) {
if (array[j] > array[j + 1]) {
swap(array, j, j + 1);
steps.push([[...array], j, j + 1, counter])
}
}
}
steps.push([[...array], -1, -1, -1]);
return steps;
}

export const bubleSortDescending = (initialArray: number[]) => {
const steps: [number[], number, number, number][] = [];
const array = [...initialArray]
const { length } = array;
let counter = length;
for (let i = 0; i < length; i++) {
counter = counter - 1;
for (let j = 0; j < length - i - 1; j++) {
if (array[j] < array[j + 1]) {
swap(array, j, j + 1);
steps.push([[...array], j, j + 1, counter])
}
}
}
steps.push([[...array], -1, -1, -1]);
return steps;
}
14 changes: 14 additions & 0 deletions src/components/stack-page/stack-page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.container {
display: flex;
gap: 10px;
}

.letterContainer {
display: flex;
width: 80%;
gap: 16px;
margin: 100px auto;
justify-content: center;
flex-wrap: wrap;
row-gap: 100px;
}
92 changes: 89 additions & 3 deletions src/components/stack-page/stack-page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,96 @@
import React from "react";
import React, { useEffect, useState } from "react";
import styles from "./stack-page.module.css";
import { SolutionLayout } from "../ui/solution-layout/solution-layout";
import { Input } from "../ui/input/input";
import { Button } from "../ui/button/button";
import { Circle } from "../ui/circle/circle";
import { ElementStates } from "../../types/element-states";
import { Stack } from "./utils";


export const StackPage: React.FC = () => {
const [string, setString] = useState<string>('');
const [stack, setStack] = useState<string[]>([]);
const [flag, setFlag] = useState<boolean>(true);
const [colorState, setColorState] = useState<boolean>(false);
const st = Stack(stack);
useEffect(() => {
if (stack.length > 0) {
setFlag(false)
} else {
setFlag(true)
}
const interval = setInterval(() => {
setColorState(false);
}, 1000);
return () => {
clearInterval(interval); }
}, [stack.length, colorState])

const handlePush = (e: any) => {
e.preventDefault();
// Read the form data
const form = e.target;
const formData = new FormData(form);
// Or you can work with it as a plain object:
const formJson = Object.fromEntries(formData.entries());
const string: any = formJson.MyInput;
st.push(string)
setString('')
setStack(st.elements())
setColorState(true)
}

const handlePop = () => {

setColorState(true)
// setStack(st.elements()) почему так не рабтает?
// setStack([...stack]) // а так работает?
setTimeout(() => {
st.pop()
setStack([...stack])
}, 1000);
}

const handleClear = () => {
st.clear()
setStack(st.elements())
}

return (
<SolutionLayout title="Стек">

<form className={styles.container} onSubmit={handlePush} >
<Input maxLength={4} isLimitText={true} name={"MyInput"} type={'text'} value={string} onChange={(evt: any) => {
setString(evt.target.value)
}} />
<Button text={"Добавить"} type={"submit"} disabled={!string} />
<Button text={"Удалить"} type={"button"} disabled={flag ? true : false} onClick={() => handlePop()} />
<Button text={"Очистить"} type={"button"} disabled={flag ? true : false} onClick={() => handleClear()} />
</form>
<div className={styles.letterContainer}>
<CircleComponent array={[...stack]} colorState={colorState} />
</div>
</SolutionLayout>
);
)
};

type CircleComponentProps = {
array: string[];
colorState: boolean;
}

const CircleComponent = ({ array, colorState }: CircleComponentProps) => {
const [flag, setFlag] = useState<boolean>(false);
useEffect(() => {
setFlag(colorState)
}, [colorState])
return (
<>
{array && array.map((item, index) => {
return <Circle letter={item.toString()} head={index === array.length - 1 ? "top" : null} tail={(index).toString()} key={index}
state={flag && index === array.length - 1 ? ElementStates.Changing : ElementStates.Default} />
})}
</>

)
}
33 changes: 33 additions & 0 deletions src/components/stack-page/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export function Stack(items: string[]) {

function push(element: string) {
return items = [...items, element]
}

function pop() {
return items.length = [...items].length - 1;
}

function elements() {
return items;
}


function size() {
return items.length;
}

function clear() {
items = [];
}

return {
clear,
push,
pop,
size,
elements
};
}

export {}
18 changes: 18 additions & 0 deletions src/components/string/string.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.container {
display: flex;
width: 55%;
gap: 12px;
margin: 0 auto;
justify-content: center;
}


.letterContainer {
display: flex;
width: 100%;
gap: 15px;
margin: 100px auto;
justify-content: center;


}
69 changes: 68 additions & 1 deletion src/components/string/string.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,77 @@
import React from "react";
import styles from "./string.module.css"
import { SolutionLayout } from "../ui/solution-layout/solution-layout";
import { Button } from "../ui/button/button";
import { Input } from "../ui/input/input";
import { Circle } from "../ui/circle/circle";
import { useState, useEffect } from "react";
import { ElementStates } from "../../types/element-states";
import { algoritm } from "./util"

export const StringComponent: React.FC = () => {
const [string, setString] = useState('');
const [isButtonPressed, setIsButtonPressed] = useState(false);
const [index, setIndex] = useState(0);
const [isLoader, setIsLoader] = useState(false);

useEffect(() => {
const interval = setInterval(() => {
if (isButtonPressed && (index < (algoritm(string).length - 1))) {
setIndex(prev => prev + 1);
}
}, 1000);
if (index === (algoritm(string).length - 1)) {
setIsLoader(false)
}

return () => { clearInterval(interval);}

}, [isButtonPressed, string, index])

const handleClick = () => {
algoritm(string);
setIsButtonPressed(true);
setIsLoader(true);
}

return (
<SolutionLayout title="Строка">

<div className={styles.container}>
<Input maxLength={11} type={"text"} isLimitText={true} onChange={(evt: any) =>
setString(evt.target.value)
} />
< Button text={'Развернуть'} onClick={handleClick} isLoader={isLoader ? true : false}/>
</div>
<div className={styles.letterContainer}>
{isButtonPressed && < CircleComponent data={algoritm(string)[index]} index={index} />}

</div>
</SolutionLayout>
);
};

type CircleComponentProps = {
data: string[];
index: number;
}

const CircleComponent = ({ data, index }: CircleComponentProps) => {
return (
<>{(index === 0) &&
data.map((item, key) => { return <Circle letter={item} key={key} state={(key === 0 || key === data.length - 1) ? ElementStates.Changing : ElementStates.Default} /> })}
{(index === 1) &&
data.map((item, key) => { return <Circle letter={item} key={key} state={(key === 0 || key === data.length - 1) ? ElementStates.Modified : (key === 1 || key === data.length - 2) ? ElementStates.Changing : ElementStates.Default} /> })}
{(index === 2) &&
data.map((item, key) => { return <Circle letter={item} key={key} state={(key <= 1 || key >= data.length - 2) ? ElementStates.Modified : (key === 2 || key === data.length - 3) ? ElementStates.Changing : ElementStates.Default} /> })}
{(index === 3) &&
data.map((item, key) => { return <Circle letter={item} key={key} state={(key <= 2 || key >= data.length - 3) ? ElementStates.Modified : (key === 3 || key === data.length - 4) ? ElementStates.Changing : ElementStates.Default} /> })}
{(index === 4) &&
data.map((item, key) => { return <Circle letter={item} key={key} state={(key <= 3 || key >= data.length - 4) ? ElementStates.Modified : (key === 4 || key === data.length - 5) ? ElementStates.Changing : ElementStates.Default} /> })}
{(index === 5) &&
data.map((item, key) => { return <Circle letter={item} key={key} state={(key <= 4 || key >= data.length - 5) ? ElementStates.Modified : (key === 5 || key === data.length - 6) ? ElementStates.Changing : ElementStates.Default} /> })}
{(index === 6) &&
data.map((item, key) => { return <Circle letter={item} key={key} state={(key <= 5 || key >= data.length - 6) ? ElementStates.Modified : (key === 6 || key === data.length - 7) ? ElementStates.Changing : ElementStates.Default} /> })}
</>

)
}
21 changes: 21 additions & 0 deletions src/components/string/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export const algoritm = (string: string) => {
const arr: string[] = [];
for (let i = 0; i < string.length; i++) {
arr.push(string[i])
}
let start = 0;
let end = arr.length - 1;
let array = [];
let data = arr.slice();
while (start < end) {
data[start] = data.splice(end, 1, data[start])[0]
start++;
end--;
array.push([...data])
}
array.unshift(arr)
if (arr.length % 2 !== 0) {
array.push(array[array.length - 1])
}
return array;
}
3,378 changes: 1,880 additions & 1,498 deletions yarn.lock

Large diffs are not rendered by default.