diff --git a/BracketSequence.Tests/BracketSequence.Tests.fsproj b/BracketSequence.Tests/BracketSequence.Tests.fsproj new file mode 100644 index 0000000..2763555 --- /dev/null +++ b/BracketSequence.Tests/BracketSequence.Tests.fsproj @@ -0,0 +1,33 @@ + + + + net7.0 + + false + true + true + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive +all + + runtime; build; native; contentfiles; analyzers; buildtransitive +all + + + + + + + + + + diff --git a/BracketSequence.Tests/BracketSequence.Tests.sln b/BracketSequence.Tests/BracketSequence.Tests.sln new file mode 100644 index 0000000..0dde088 --- /dev/null +++ b/BracketSequence.Tests/BracketSequence.Tests.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 25.0.1706.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "BracketSequence.Tests", "BracketSequence.Tests.fsproj", "{2B02A4C0-83AC-48BE-BDAD-C3935BA442E6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2B02A4C0-83AC-48BE-BDAD-C3935BA442E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B02A4C0-83AC-48BE-BDAD-C3935BA442E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B02A4C0-83AC-48BE-BDAD-C3935BA442E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B02A4C0-83AC-48BE-BDAD-C3935BA442E6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7EFC385E-DD21-4D37-9CB3-4FF735185470} + EndGlobalSection +EndGlobal diff --git a/BracketSequence.Tests/BracketSequenceTest.fs b/BracketSequence.Tests/BracketSequenceTest.fs new file mode 100644 index 0000000..ca40300 --- /dev/null +++ b/BracketSequence.Tests/BracketSequenceTest.fs @@ -0,0 +1,29 @@ +module BracketSequence.Tests + +open NUnit.Framework +open FsUnit +open BracketSequenceChecker + +[] +let ``Function checks correctly sequence of brackets`` () = + let brSeqCorr = "(({})[])" + let brSeqIncorr = "((({})[])" + + (isCorrectBracketSequence brSeqCorr, isCorrectBracketSequence brSeqIncorr) + |> should equal (true, false) + +[] +let ``Function checks correctly sequence of brackets with other symbols`` () = + let brSeq = "(t({}d)[]g)" + + isCorrectBracketSequence brSeq |> should be True + +[] +let ``Function checks correctly empty string`` () = + isCorrectBracketSequence "" |> should be True + +[] +let ``Function checks correctly string with no braskets`` () = + let brSeq = "abc" + + isCorrectBracketSequence brSeq |> should be True diff --git a/BracketSequence/BracketSequence.fs b/BracketSequence/BracketSequence.fs new file mode 100644 index 0000000..b46a4c6 --- /dev/null +++ b/BracketSequence/BracketSequence.fs @@ -0,0 +1,32 @@ +namespace BracketSequence + +module BracketSequenceChecker = + let bracketList = Map [(')', '('); ('}', '{'); (']', '[')] + + let isOpen (bracket: char) = + bracket = '(' || bracket = '{' || bracket = '[' + + let isClose (bracket: char) = + bracket = ']' || bracket = ')' || bracket = '}' + + let getRelativeOpen (bracket: char) = bracketList.[bracket] + + let isCorrectBracketSequence (bracketString: string) = + let rec internalBracketSequenceChecker charList bracketsStack = + match charList with + | fstChar :: tail -> + if isOpen fstChar then + internalBracketSequenceChecker tail (fstChar :: bracketsStack) + elif isClose fstChar then + match bracketsStack with + | lastBracket :: brackets -> + if lastBracket = getRelativeOpen (fstChar) then + internalBracketSequenceChecker tail brackets + else + false + | _ -> false + else + internalBracketSequenceChecker tail bracketsStack + | [] -> bracketsStack = [] + + internalBracketSequenceChecker (bracketString |> Seq.toList) [] diff --git a/BracketSequence/BracketSequence.fsproj b/BracketSequence/BracketSequence.fsproj new file mode 100644 index 0000000..51cae49 --- /dev/null +++ b/BracketSequence/BracketSequence.fsproj @@ -0,0 +1,12 @@ + + + + net7.0 + true + + + + + + + diff --git a/BracketSequence/BracketSequence.sln b/BracketSequence/BracketSequence.sln new file mode 100644 index 0000000..0780b8c --- /dev/null +++ b/BracketSequence/BracketSequence.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 25.0.1706.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "BracketSequence", "BracketSequence.fsproj", "{A2CB2149-29E8-46F6-886C-2055C0147B2D}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "BracketSequence.Tests", "..\BracketSequence.Tests\BracketSequence.Tests.fsproj", "{7E89457D-5A00-410F-A24F-50F10C906788}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A2CB2149-29E8-46F6-886C-2055C0147B2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A2CB2149-29E8-46F6-886C-2055C0147B2D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A2CB2149-29E8-46F6-886C-2055C0147B2D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A2CB2149-29E8-46F6-886C-2055C0147B2D}.Release|Any CPU.Build.0 = Release|Any CPU + {7E89457D-5A00-410F-A24F-50F10C906788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E89457D-5A00-410F-A24F-50F10C906788}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E89457D-5A00-410F-A24F-50F10C906788}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E89457D-5A00-410F-A24F-50F10C906788}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B3D8A4FD-3A28-4BCD-BFD8-85BD77F30461} + EndGlobalSection +EndGlobal diff --git a/PhoneBook.Tests/PhoneBook.Tests.fsproj b/PhoneBook.Tests/PhoneBook.Tests.fsproj new file mode 100644 index 0000000..f97a0e9 --- /dev/null +++ b/PhoneBook.Tests/PhoneBook.Tests.fsproj @@ -0,0 +1,36 @@ + + + + net7.0 + + false + true + true + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive +all + + runtime; build; native; contentfiles; analyzers; buildtransitive +all + + + + + + + + + + + + + diff --git a/PhoneBook.Tests/PhoneBookTests.fs b/PhoneBook.Tests/PhoneBookTests.fs new file mode 100644 index 0000000..1ba906b --- /dev/null +++ b/PhoneBook.Tests/PhoneBookTests.fs @@ -0,0 +1,82 @@ +module PhoneBook.Tests + +open NUnit.Framework +open FsUnit +open System.IO +open PhoneBook + +let testFilePath = "testFileBase.txt" + +let contactMax = ({ Name = "Max"; Phone = "123" }) +let contactVasya = ({ Name = "Vasya"; Phone = "124" }) + +[] +let ``Write and read test`` () = + File.WriteAllText(testFilePath, "") + let data = [ contactMax; contactMax ] + writeContactsToFile data testFilePath + readContactsFromFile testFilePath |> should equal data + +[] +let ``Add new record test`` () = + let data = [ contactMax ] + + let expected = ([ contactVasya; contactMax ], true) + + addContactToBase "Vasya" "124" data |> should equal expected + +[] +let ``Can not add record with existed in base phone or name`` () = + let data = [ contactMax ] + let (newData, _) = addContactToBase "Vasya" "123" data + let (newNewData, _) = addContactToBase "Max" "345" newData + (newNewData, newData) |> should equal (data, data) + +[] +let ``Finding ny name and phone test`` () = + let name = "Max" + let phone = "123" + let data = [ contactMax ] + let res1 = findContactByNameInBase name data + let res2 = findContactByPhoneInBase phone data + + (res1, res2) |> should equal (Some(contactMax), Some(contactMax)) + +[] +let ``isContactInFile test`` () = + let name = "Max" + let phone = "123" + File.WriteAllText(testFilePath, "") + let data = [ contactMax ] + writeContactsToFile data testFilePath + isContactInFile name phone testFilePath |> should be True + +[] +let ``isContactInBase test`` () = + let data = [ contactMax ] + + isContactInBase "Max" "123" data |> should be True + +[] +let ``Write contacts from base to file test`` () = + File.WriteAllText(testFilePath, "") + + let phoneBase = [ contactVasya; contactMax ] + + writeContactsToFile phoneBase testFilePath + readContactsFromFile testFilePath |> should equal phoneBase + +[] +let ``Write contactMaxs from file to base`` () = + File.WriteAllText(testFilePath, "") + + let data = [ contactMax; contactVasya ] + + writeContactsToFile data testFilePath + + writePhoneBaseFromFile testFilePath |> should equal data + +[] +let ``Correct phone test`` () = + (isCorrectPhone "88005555", isCorrectPhone "880055d5") + |> should equal (true, false) diff --git a/PhoneBook/PhoneBook.fs b/PhoneBook/PhoneBook.fs new file mode 100644 index 0000000..cbec47b --- /dev/null +++ b/PhoneBook/PhoneBook.fs @@ -0,0 +1,54 @@ +namespace PhoneBook + +open System.IO +open System.Text.RegularExpressions +open Newtonsoft.Json + +module PhoneBook = + type Contact = { Name: string; Phone: string } + + let readContactsFromFile phoneBaseFile = + if File.Exists(phoneBaseFile) then + let json = File.ReadAllText(phoneBaseFile) + + if json = "" then + [] + else + JsonConvert.DeserializeObject(json) + else + [] + + let writeContactsToFile (contacts: Contact list) phoneBaseFile = + if contacts = [] then + () + else + let json = + JsonConvert.SerializeObject((contacts @ (readContactsFromFile phoneBaseFile)), Formatting.Indented) + + File.WriteAllText(phoneBaseFile, json) + + let isContactInFile nameForFind phoneToFind phoneBaseFile = + List.exists (fun contact -> contact.Name = nameForFind || contact.Phone = phoneToFind) + <| readContactsFromFile phoneBaseFile + + let isContactInBase nameForFind phoneToFind phoneBase = + List.exists (fun contact -> contact.Name = nameForFind || contact.Phone = phoneToFind) phoneBase + + let writePhoneBaseFromFile phoneBaseFile = readContactsFromFile phoneBaseFile + + let isCorrectPhone (phone: string) = + let pattern = @"^[0-9]+$" + let regex = new Regex(pattern) + regex.IsMatch(phone) + + let addContactToBase name phone (phoneBase: Contact List) = + if (not (isContactInBase name phone phoneBase)) && isCorrectPhone (phone) then + (({ Name = name; Phone = phone } :: phoneBase), true) + else + (phoneBase, false) + + let findContactByPhoneInBase phone (phoneBase: Contact List) = + List.tryFind (fun contact -> contact.Phone = phone) phoneBase + + let findContactByNameInBase name (phoneBase: Contact List) = + List.tryFind (fun contact -> contact.Name = name) phoneBase diff --git a/PhoneBook/PhoneBook.fsproj b/PhoneBook/PhoneBook.fsproj new file mode 100644 index 0000000..a86bfeb --- /dev/null +++ b/PhoneBook/PhoneBook.fsproj @@ -0,0 +1,21 @@ + + + + Exe + net7.0 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PhoneBook/PhoneBook.sln b/PhoneBook/PhoneBook.sln new file mode 100644 index 0000000..2916851 --- /dev/null +++ b/PhoneBook/PhoneBook.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 25.0.1706.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PhoneBook", "PhoneBook.fsproj", "{628FF28C-A8BC-4E9E-9B00-1E61DA100811}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PhoneBook.Tests", "..\PhoneBook.Tests\PhoneBook.Tests.fsproj", "{443CCD9A-A63A-4874-9FC3-22685C16E1F2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {628FF28C-A8BC-4E9E-9B00-1E61DA100811}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {628FF28C-A8BC-4E9E-9B00-1E61DA100811}.Debug|Any CPU.Build.0 = Debug|Any CPU + {628FF28C-A8BC-4E9E-9B00-1E61DA100811}.Release|Any CPU.ActiveCfg = Release|Any CPU + {628FF28C-A8BC-4E9E-9B00-1E61DA100811}.Release|Any CPU.Build.0 = Release|Any CPU + {443CCD9A-A63A-4874-9FC3-22685C16E1F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {443CCD9A-A63A-4874-9FC3-22685C16E1F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {443CCD9A-A63A-4874-9FC3-22685C16E1F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {443CCD9A-A63A-4874-9FC3-22685C16E1F2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DE39838F-555F-4B22-BF4A-9189FD1CA344} + EndGlobalSection +EndGlobal diff --git a/PhoneBook/Program.fs b/PhoneBook/Program.fs new file mode 100644 index 0000000..767281a --- /dev/null +++ b/PhoneBook/Program.fs @@ -0,0 +1,113 @@ +open System +open PhoneBook.PhoneBook + +let printInstructions () = + printfn "It's a phone book!" + printfn "You can enter command number to:" + printfn "1. Add new record" + printfn "2. Find contact by phone" + printfn "3. Find contact by name" + printfn "4. Print current phone book" + printfn "5. Print contacts from file" + printfn "6. Add contacts from current phone book to file" + printfn "7. Exit" + +let phoneBaseFile = "PhoneBase.txt" + +let stringContact contact = + printfn "%s - %s" contact.Name contact.Phone + +let printContactList (contactList: Contact list) = + if List.isEmpty contactList then + printfn "There are no contacts\n" + else + let rec printContactListInternal ls = + match ls with + | h :: tail -> + stringContact h + printContactListInternal tail + | _ -> () + + printContactListInternal contactList + +let rec enterCorrectPhone () = + printfn "Enter phone: " + let phone = Console.ReadLine() + + if isCorrectPhone (phone) then + phone + else + printfn "Phone was incorrect\n" + enterCorrectPhone () + +let addNewRecord (phoneBase: Contact list) = + printfn "To add new record enter name: " + let name = Console.ReadLine() + let phone = enterCorrectPhone () + + match addContactToBase name phone phoneBase with + | (newPhoneBase, true) -> + printfn "Contact added successfully!\n" + newPhoneBase + | _ -> + printfn "Contact wasn't added: phone or name are already in phone book!\n" + phoneBase + +let printFindingRes (result: Contact option) = + match result with + | Some contact -> + printfn "Contact was found: " + stringContact contact + | None -> printfn "Contact wasn't found!" + +let findPhoneByName (phoneBase: Contact list) = + let phone = enterCorrectPhone () + printFindingRes (findContactByPhoneInBase phone phoneBase) + +let findNameByPhone (phoneBase: Contact list) = + printfn "Enter name: " + let name = Console.ReadLine() + printFindingRes (findContactByNameInBase name phoneBase) + +let printCurrentPhoneBook (phoneBase: Contact list) = + printfn "Current phone book:\n" + printContactList phoneBase + +let printContactsFromFile () = + printfn "Contacts in file:" + printContactList (readContactsFromFile phoneBaseFile) + +let addContactsToFile (phoneBase: Contact list) = + writeContactsToFile phoneBase phoneBaseFile + +let run = + let rec internalRun (phoneBase: Contact list) = + printInstructions () + printfn "Enter command: " + let command = Console.ReadLine() + + match command with + | "1" -> + let newPhoneBase = addNewRecord phoneBase + internalRun newPhoneBase + | "2" -> + findPhoneByName phoneBase + internalRun phoneBase + | "3" -> + findNameByPhone phoneBase + internalRun phoneBase + | "4" -> + printCurrentPhoneBook phoneBase + internalRun phoneBase + | "5" -> + printContactsFromFile () + internalRun phoneBase + | "6" -> + addContactsToFile phoneBase + internalRun phoneBase + | "7" -> printfn "Exit" + | _ -> + printfn "Incorrect command!\n" + internalRun phoneBase + + internalRun (writePhoneBaseFromFile phoneBaseFile) diff --git a/PointFree.Tests/PointFree.Tests.fsproj b/PointFree.Tests/PointFree.Tests.fsproj new file mode 100644 index 0000000..e786e9a --- /dev/null +++ b/PointFree.Tests/PointFree.Tests.fsproj @@ -0,0 +1,37 @@ + + + + net7.0 + + false + false + true + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive +all + + runtime; build; native; contentfiles; analyzers; buildtransitive +all + + + + + + + + + + + + + diff --git a/PointFree.Tests/PointFreeTest.fs b/PointFree.Tests/PointFreeTest.fs new file mode 100644 index 0000000..5bab7cf --- /dev/null +++ b/PointFree.Tests/PointFreeTest.fs @@ -0,0 +1,16 @@ +module PointFree.Tests + +open NUnit.Framework +open FsCheck +open PointFree + + +[] +let ``Functions are equal`` () = + let functionResAreEq (x: int) (l: int list) = + (func'1 x l = func'2 x l) + && (func'2 x l = func'3 x l) + && (func'3 x l = func'4 x l) + && (func'4 x l = func'5 x l) + + Check.QuickThrowOnFailure functionResAreEq diff --git a/PointFree.Tests/Program.fs b/PointFree.Tests/Program.fs new file mode 100644 index 0000000..5fa22d1 --- /dev/null +++ b/PointFree.Tests/Program.fs @@ -0,0 +1,4 @@ +module Program = + + [] + let main _ = 0 diff --git a/PointFree/PointFree.fs b/PointFree/PointFree.fs new file mode 100644 index 0000000..9760a01 --- /dev/null +++ b/PointFree/PointFree.fs @@ -0,0 +1,13 @@ +namespace PointFree + +module PointFree = + + let func'1 x l = List.map (fun y -> y * x) l + + let func'2 x = List.map (fun y -> y * x) + + let func'3 x = List.map (fun y -> (*) y x) + + let func'4 x = List.map ((*) x) + + let func'5 = List.map << (*) diff --git a/PointFree/PointFree.fsproj b/PointFree/PointFree.fsproj new file mode 100644 index 0000000..d49e68a --- /dev/null +++ b/PointFree/PointFree.fsproj @@ -0,0 +1,12 @@ + + + + net7.0 + true + + + + + + + diff --git a/PointFree/PointFree.sln b/PointFree/PointFree.sln new file mode 100644 index 0000000..2a27ac9 --- /dev/null +++ b/PointFree/PointFree.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 25.0.1706.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PointFree", "PointFree.fsproj", "{2BED6737-912E-4273-B30E-ED0DB93363C4}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "PointFree.Tests", "..\PointFree.Tests\PointFree.Tests.fsproj", "{2A7F66CA-078A-42A6-AD6B-C2051975BE6B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2BED6737-912E-4273-B30E-ED0DB93363C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2BED6737-912E-4273-B30E-ED0DB93363C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2BED6737-912E-4273-B30E-ED0DB93363C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2BED6737-912E-4273-B30E-ED0DB93363C4}.Release|Any CPU.Build.0 = Release|Any CPU + {2A7F66CA-078A-42A6-AD6B-C2051975BE6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A7F66CA-078A-42A6-AD6B-C2051975BE6B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A7F66CA-078A-42A6-AD6B-C2051975BE6B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A7F66CA-078A-42A6-AD6B-C2051975BE6B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {CB1E270B-8D1D-4072-A2E7-0C57406967F1} + EndGlobalSection +EndGlobal