diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..46f164f20f7c863817d115cff8cbc69adc81248c --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +NAME=solution + +all: haskell + +haskell: + ghc $(NAME).hs -o $(NAME)-haskell + rm $(NAME).hi $(NAME).o + +uploadfile: + curl -F file=input1.txt localhost:8000/uploadfile + +webservice: + ghc -threaded ws.hs -o ws + rm ws.hi ws.o + +clean: + rm -f *.hi *.o $(NAME) + diff --git a/exercise.txt b/exercise.txt new file mode 100644 index 0000000000000000000000000000000000000000..05c60b9f9b4cae46f059bb2ba2eee4f1c8091c96 --- /dev/null +++ b/exercise.txt @@ -0,0 +1,52 @@ +Reward system + +A company is planning a way to reward customers for inviting their friends. +They're planning a reward system that will give a customer points for each +confirmed invitation they played a part into. The definition of a confirmed +invitation is one where another invitation's invitee invited someone. + +The inviter gets (1/2)^k points for each confirmed invitation, where k is the +level of the invitation: level 0 (people directly invited) yields 1 point, +level 1 (people invited by someone invited by the original customer) gives 1/2 +points, level 2 invitations (people invited by someone on level 1) awards 1/4 +points and so on. Only the first invitation counts: multiple invites sent to +the same person don't produce any further points, even if they come from +different inviters. + +Also, to count as a valid invitation, the invited customer must have invited +someone (so customers that didn't invite anyone don't count as points for the +customer that invited them). + +So, given the input: +1 2 +1 3 +3 4 +2 4 +4 5 +4 6 + +The score is: +1 - 2.5 (2 because he invited 2 and 3 plus 0.5 as 3 invited 4) +3 - 1 (1 as 3 invited 4 and 4 invited someone) +2 - 0 (even as 2 invited 4, it doesn't count as 4 was invited before by 3) +4 - 0 (invited 5 and 6, but 5 and 6 didn't invite anyone) +5 - 0 (no further invites) +6 - 0 (no further invites) + +Note that 2 invited 4, but, since 3 invited 4 first, customer 3 gets the +points. + +Write a program that receives a text file with the input and exposes the +ranking on a JSON format on a HTTP endpoint. Also, create another endpoint to +add a new invitation. + +You should deliver a git repository, or a link to a shared private repository +on GitHub, Bitbucket or similar, with your code and a short README file +outlining the solution and explaining how to build and run the code. You should +follow the functional programming paradigm — Clojure, Common Lisp, Scheme, +Haskell, ML, F# and Scala are acceptable languages — and we'll analyse the +structure and readability of the codebase. We expect production-grade code. +There is no problem in using libraries, for instance for testing or network +interaction, but please refrain from using a library that already implements +the core algorithms to solve this problem (e.g. tree or graph algorithms). + diff --git a/input1.txt b/input1.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c4707fd7a8b9f7bc9feeb01f1ff395a3b38e8bd --- /dev/null +++ b/input1.txt @@ -0,0 +1,7 @@ +1 2 +1 3 +3 4 +2 4 +4 5 +4 6 + diff --git a/input2.txt b/input2.txt new file mode 100644 index 0000000000000000000000000000000000000000..4894aad157ac277bbf6d67a8e655c4960bb8dc82 --- /dev/null +++ b/input2.txt @@ -0,0 +1,200 @@ +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +11 12 +12 13 +13 14 +14 15 +15 16 +16 17 +17 18 +18 19 +19 20 +20 21 +21 22 +22 23 +23 24 +24 25 +25 26 +26 27 +27 28 +28 29 +29 30 +30 31 +31 32 +32 33 +33 34 +34 35 +35 36 +36 37 +37 38 +38 39 +39 40 +40 41 +41 42 +42 43 +43 44 +44 45 +45 46 +46 47 +47 48 +48 49 +49 50 +50 51 +51 101 +50 52 +52 102 +50 53 +53 103 +50 54 +54 104 +50 55 +55 105 +50 56 +56 106 +50 57 +57 107 +50 58 +58 108 +50 59 +59 109 +50 60 +60 110 +50 61 +61 111 +50 62 +62 112 +50 63 +63 113 +50 64 +64 114 +50 65 +65 115 +50 66 +66 116 +50 67 +67 117 +50 68 +68 118 +50 69 +69 119 +50 70 +70 120 +50 71 +71 121 +50 72 +72 122 +50 73 +73 123 +50 74 +74 124 +50 75 +75 125 +50 76 +76 126 +50 77 +77 127 +50 78 +78 128 +50 79 +79 129 +50 80 +80 130 +50 81 +81 131 +50 82 +82 132 +50 83 +83 133 +50 84 +84 134 +50 85 +85 135 +50 86 +86 136 +50 87 +87 137 +50 88 +88 138 +50 89 +89 139 +50 90 +90 140 +50 91 +91 141 +50 92 +92 142 +50 93 +93 143 +50 94 +94 144 +50 95 +95 145 +50 96 +96 146 +50 97 +97 147 +50 98 +98 148 +50 99 +99 149 +50 100 +100 150 +69 70 +70 53 +52 54 +59 21 +86 9 +94 43 +59 96 +15 69 +15 40 +93 2 +77 52 +74 66 +39 81 +8 18 +61 68 +63 15 +51 50 +93 77 +28 91 +23 22 +42 1 +95 96 +53 53 +1 46 +10 49 +34 26 +80 21 +88 94 +11 10 +80 24 +10 100 +20 110 +30 120 +30 130 +40 140 +50 150 +60 160 +80 100 +90 100 +56 100 +12 10 +10 12 +100 56 +100 90 +40 140 +10 150 +11 180 +10 190 +24 48 +25 49 +16 48 diff --git a/solution.hs b/solution.hs new file mode 100644 index 0000000000000000000000000000000000000000..69c5d3a6807ca401c819863e1f32865419cf98c3 --- /dev/null +++ b/solution.hs @@ -0,0 +1,52 @@ +import System.IO +import Control.Monad +import Data.Map (Map) +import qualified Data.Map as Map + +main = do + inputStr <- readFile "input1.txt" + print (parent (getInput inputStr)) + + +{-| +getInput: Convert the input into a list of pairs. Por example, if the input is +---------------------------- +1 2 +1 3 +3 4 +2 4 +4 5 +4 6 + +---------------------------- +the returnet list is: [[1,2],[1,3],[3,4],[2,4],[4,5],[4,6]] +-} + +getInput :: String -> [[Int]] +getInput s = map (map read) . map words . filter (not . null) . lines $ s + +{-| +the function Map.fromList creates a map from a list. For example: + +Prelude Data.Map Map> Map.fromList([(1,1),(2,2),(3,3)]) +fromList [(1,1),(2,2),(3,3)] + +and + +Prelude Data.Map Map> Map.fromList [(1,1),(2,2),(3,3),(1,4),(1,5)] +fromList [(1,5),(2,2),(3,3)] + +We use this function to compute the parent of each node, when it exists. +Every time that we have an edge of the form + +i -> j + +we add (j, i) to the map, indicating that the parent of j is i. + +Given that the value is overwritten and we want the first, we reverse the list +-} + +parent :: [[Int]] -> Map Int Int +parent xs = Map.fromList (map makePair (reverse (map reverse xs))) + where makePair x = (x!!0, x!!1) +