diff --git a/Challenges.hs b/Challenges.hs
new file mode 100644
index 0000000000000000000000000000000000000000..f5b6fef11e070ed7974e95eb56bd771f75f5a5f8
--- /dev/null
+++ b/Challenges.hs
@@ -0,0 +1,404 @@
+{-# LANGUAGE DeriveGeneric #-}
+-- comp2209 Functional Programming Challenges
+-- (c) University of Southampton 2022
+-- Skeleton code to be updated with your solutions
+-- The dummy functions here simply return an arbitrary value that is usually wrong 
+
+-- DO NOT MODIFY THE FOLLOWING LINES OF CODE
+module Challenges (Atoms,Interactions,Pos,EdgePos,Side(..),Marking(..),
+                   LamExpr(..),ArithExpr(..),
+                   calcBBInteractions,solveBB,prettyPrint,
+                   parseArith,churchEnc,innerRedn1,innerArithRedn1,compareArithLam) where
+
+
+-- Import standard library and parsing definitions from Hutton 2016, Chapter 13
+import Data.Char
+import Parsing
+import Control.Monad
+import Data.List
+import GHC.Generics (Generic,Generic1)
+import Control.DeepSeq
+import Data.Maybe
+import Data.Ord
+import Data.Function
+
+
+
+
+-- Challenge 1
+-- Calculate Interactions in the Black Box
+
+type Atoms = [ Pos ]
+type Interactions = [  ( EdgePos , Marking )  ] 
+type Pos = (Int, Int)   -- top left is (1,1) , bottom right is (N,N) where N is size of grid
+type EdgePos = ( Side , Int ) -- int range is 1 to N where N is size of grid
+type Corners = [(Angel,Pos)]
+type RayPath = (Side,Atoms) 
+
+
+data Side = North | East | South | West
+            deriving (Show, Eq, Ord, Generic)
+
+data Marking =  Absorb | Reflect | Path EdgePos
+                deriving (Show, Eq)
+data Angel = Lt | Rt | Lb | Rb 
+                deriving (Show, Eq)               
+
+
+calcBBInteractions :: Int -> Atoms -> [EdgePos] -> Interactions
+calcBBInteractions limit atoms positions | limit < 1 = error "grid must be larger than 0*0"
+calcBBInteractions limit atoms [] = []
+calcBBInteractions limit atoms (x:xs) | checkEdgeReflection ( head(snd coordinates)) atoms (fst x) = (x,Reflect) : calcBBInteractions limit atoms xs
+                                      | otherwise = traverseGraph coordinates atoms corners (x,limit) : calcBBInteractions limit atoms xs
+                                        where coordinates = pathCreator x limit 
+                                              corners = cornerCreator atoms
+
+createGrid n = [(y,x) | x <- [1..n],y <- [1..n]]
+
+cornerCreator :: Atoms -> Corners
+cornerCreator [] = []
+cornerCreator ((y,z):xs) = (Rb,(y+1,z+1)):(Rt,(y+1,z-1)):(Lb,(y-1,z+1)):(Lt,(y-1,z-1)):cornerCreator xs
+
+pathCreator :: EdgePos -> Int -> RayPath
+pathCreator (North,n) t = (South,[(n,x)| x <- [1..t+1]])
+pathCreator (East,n) t = (West,[(x,n) | x <- [t,t-1..0]])
+pathCreator (South,n) t = (North,[(n,x) | x <- [t,t-1..0]])
+pathCreator (West,n) t = (East,[(x,n) | x <- [1..t+1]])
+
+checkEdgeReflection :: (Int,Int) -> Atoms -> Side -> Bool
+checkEdgeReflection x [] side  = False
+checkEdgeReflection x ((z,w):ys) side  | x `elem` ((z,w):ys) = False
+                                  |(side == North || side == South) && (x == (z+1,w))  = True
+                                  | (side == North || side == South) && (x == (z-1,w))  = True
+                                  | (side == West || side == East) && (x == (z,w+1))  = True
+                                  | (side == West || side == East) && x == ((z,w-1))  = True
+                                  | otherwise = checkEdgeReflection x ys side
+                                  
+traverseGraph :: RayPath -> Atoms -> Corners ->  (EdgePos,Int) -> (EdgePos,Marking)
+
+traverseGraph (North,(x:xs)) atoms corners start | (snd x) == 0 = ((fst start),Path (North,(fst x)))
+                                                 | x `elem` atoms = ((fst start),Absorb)
+                                                 | length(y) == 2 && ((fst x),(snd x)-1) `notElem` atoms = ((fst start),Reflect)
+                                                 | length(y) > 0 && ((fst x),(snd x)-1) `notElem` atoms = traverseGraph (deflect North y (snd start)) atoms corners start
+                                                 | otherwise = traverseGraph (North,(xs)) atoms corners start
+                                                  where y = find' x corners
+                                                  
+traverseGraph (East,(x:xs)) atoms corners start  | (fst x) > (snd start) = ((fst start),Path (East,(snd x)))
+                                                  | x `elem` atoms = ((fst start),Absorb)
+                                                  | length(y) == 2 && ((fst x)+1,(snd x)) `notElem` atoms = ((fst start),Reflect)
+                                                  | length(y) > 0 && ((fst x)+1,(snd x)) `notElem` atoms = traverseGraph (deflect East y (snd start)) atoms corners start
+                                                  | otherwise = traverseGraph (East,(xs)) atoms corners start
+                                                  where y = find' x corners
+traverseGraph (South,(x:xs)) atoms corners start | (snd x) > (snd start) = ((fst start),Path (South,(fst x)))
+                                                 | x `elem` atoms = ((fst start),Absorb)
+                                                 | length(y) == 2 && ((fst x),(snd x)+1) `notElem` atoms = ((fst start),Reflect)
+                                                 | length(y) > 0 && ((fst x),(snd x)+1) `notElem` atoms = traverseGraph (deflect South y (snd start)) atoms corners start
+                                                 | otherwise = traverseGraph (South,(xs)) atoms corners start
+                                                  where y = find' x corners
+traverseGraph (West,(x:xs)) atoms corners start | (fst x) == 0 = ((fst start),Path (West,(snd x)))
+                                                  | x `elem` atoms = ((fst start),Absorb)
+                                                  | length(y) == 2 && ((fst x)-1,(snd x)) `notElem` atoms = ((fst start),Reflect)
+                                                  | length(y) == 1 && ((fst x)-1,(snd x)) `notElem` atoms = traverseGraph (deflect West y (snd start)) atoms corners start
+                                                  | otherwise = traverseGraph (West,(xs)) atoms corners start
+                                                  where y = find' x corners
+                                         
+                     
+
+
+deflect :: Side -> Corners -> Int -> RayPath
+deflect North corners limit | (fst (head corners)) == Rb = (East,[(z,y) | z <- [x+1..limit+1] ])
+                            | (fst (head corners)) == Lb = (West,[(z,y) | z <- [x-1,x-2..0]])
+                            |(fst (head corners)) == Lt = (West,[(z,y) | z <- [x-1,x-2..0]])
+                            | (fst (head corners)) == Rt = (East,[(z,y) | z <- [x+1..limit+1] ])
+                            | otherwise = (North,[])
+                                 where x = fst.snd.head $ corners
+                                       y = snd.snd.head $ corners
+deflect East corners limit  | (fst (head corners)) == Lb = (South,[(x,z) | z <- [y+1..limit+1] ])
+                            | (fst (head corners)) == Lt = (North,[(x,z) | z <- [y-1,y-2..0]])
+                            | (fst (head corners)) == Rt = (North,[(x,z) | z <- [y-1,y-2..0]])
+                            | (fst (head corners)) == Lb = (South,[(x,z) | z <- [y+1..limit+1] ])
+                            | otherwise = (East,[])
+                                  where x = fst.snd.head $ corners
+                                        y = snd.snd.head $ corners
+deflect South corners limit | (fst (head corners)) == Rt || (fst (head corners)) == Rb   = (East,[(z,y) | z <- [x+1..limit+1] ])
+                            | (fst (head corners)) == Lt || (fst (head corners)) == Lb = (West,[(z,y) | z <- [x-1,x-2..0]])
+                            | otherwise = (South,[])
+                               where x = fst.snd.head $ corners
+                                     y = snd.snd.head $ corners
+deflect West corners limit   | (fst (head corners)) == Rb || (fst (head corners))==Lb = (South,[(x,z) | z <- [y+1..limit+1]])
+                             | (fst (head corners)) == Rt || (fst (head corners)) == Lt = (North,[(x,z) | z <- [y-1,y-2..0]])
+                             | otherwise = (West,[])
+                                where x = fst.snd.head $ corners
+                                      y = snd.snd.head $ corners
+ 
+
+find' k t =[(z,v)|(z,v)<-t,k==v]
+                                      
+-- Challenge 2
+-- Find atoms in a Black Box
+data Deflections = Up | Down | DRight | DLeft 
+
+solveBB :: Int -> Interactions -> Atoms 
+solveBB limit xs = smallestList( filter (not.null)(filterAtums limit xs (powerset (possibleAtoms limit xs [])))) 
+                     
+
+-- this give a possible set of atoms 
+possibleAtoms limit [] ys = ys
+possibleAtoms limit (x:xs) ys | calcBBInteractions limit ys [fst x] == [x] = possibleAtoms limit xs ys
+                              | checkNormal x = possibleAtoms limit xs (subsetNormal ys x limit (automSetNormal limit x))
+                              | otherwise = possibleAtoms limit xs (subsetAbnormal ys x limit (automSetAbnormal limit x))
+                              
+
+subsetNormal ys interaction limit [] = ys
+subsetNormal ys interaction limit (x:xs) | calcBBInteractions limit (ys++[x]) [(fst interaction)] == [interaction] = subsetNormal (ys++[x]) interaction limit xs
+                                         | otherwise = subsetNormal ys interaction limit xs
+
+subsetAbnormal ys interaction limit [] = ys
+subsetAbnormal ys interaction limit (x:xs) | calcBBInteractions limit (ys++x) [(fst interaction)] == [interaction] = subsetAbnormal (ys++x) interaction limit xs
+                                           | otherwise = subsetAbnormal ys interaction limit xs 
+
+checkNormal ((North,n),Path (z,x)) | (z == South || z == North) && n/= x = False
+                                 | otherwise = True
+checkNormal ((South,n),Path (z,x)) | (z == South || z == North) && n/= x = False
+                                 | otherwise = True
+checkNormal ((West,n),Path (z,x)) | (z == West || z == East) && n/= x = False
+                                 | otherwise = True
+checkNormal ((East,n),Path (z,x)) | (z == East || z == West) && n/= x = False
+                                 | otherwise = True                             
+checkNormal (x,Reflect) = True                                                                      
+checkNormal (x,Absorb) = True                                  
+                                                            
+automSetNormal limit (z,y) = filter (\x -> helper1 limit [x] z (z,y)) (coordinates limit)
+automSetAbnormal limit (z,y) = concat(filter (not.null)(map (filter (\x -> helper1 limit x z (z,y)))(atomsSubs (coordinates limit))))   
+
+coordinates limit = [(x,y) | x <- [1..limit], y <- [1..limit]]  
+helper1 limit xs y interaction | calcBBInteractions limit xs [y] == [interaction] = True
+                              | otherwise = False  
+
+
+
+atomsSubs [] = []
+atomsSubs (x:xs) = helpme x xs : atomsSubs xs 
+
+helpme z xs = map (\x -> [z,x])xs
+filterAtums :: Int -> Interactions -> [Atoms]  -> [Atoms]
+
+filterAtums limit zs (ys) = filter (\x -> (calcBBInteractions limit x (map fst zs) == zs)) ys
+smallestList :: [[a]] -> [a]
+smallestList = minimumBy (compare `on` length)
+powerset :: [a] -> [[a]]
+powerset [] = [[]]
+powerset (x:xs) = let ps = powerset xs in ps ++ [x:s | s <- ps]
+
+
+-- Challenge 3
+-- Pretty Printing Lambda with Alpha-Normalisation 
+
+data LamExpr =  LamApp LamExpr LamExpr  |  LamAbs Int LamExpr  |  LamVar Int 
+                deriving (Eq, Show, Read)
+
+prettyPrint :: LamExpr -> String
+
+prettyPrint x = printExp (fixingLambdas x 0) 
+{- turning the lambda expressions into alpha normal form-}
+fixingLambdas :: LamExpr -> Int -> LamExpr
+fixingLambdas (LamVar x) y | x < 0 = error " no negative variables"
+                           |otherwise = LamVar x
+fixingLambdas (LamAbs x e1) y | y == x = LamAbs x (fixingLambdas e1 0)
+                              | free y e1 = fixingLambdas (LamAbs x e1) (y+1) 
+                              | not (free x e1) = LamAbs y (fixingLambdas e1 0)
+                              | otherwise = LamAbs y (fixingLambdas (renameFree x e1 y) 0)
+                                 
+fixingLambdas (LamApp e1 e2) y = LamApp (fixingLambdas e1 y) (fixingLambdas e2 y)
+
+{- renames free variables of x in e1 to y  -}
+
+renameFree :: Int -> LamExpr -> Int -> LamExpr
+renameFree old (LamVar x) new | x == old = LamVar new
+                              | otherwise = LamVar x
+renameFree old (LamAbs x e1) new = LamAbs x (renameFree old e1 new)
+renameFree old (LamApp e1 e2) new | ( free old e1 ) && (free old e2) = LamApp (renameFree old e1 new) (renameFree old e2 new)
+                                  | ( free old e1 ) = LamApp (renameFree old e1 new) e2
+                                  | otherwise = LamApp e1 (renameFree old e2 new)
+                                 
+{- used it from lecture notes with a little bit adjustment  -}
+free :: Int -> LamExpr -> Bool 
+free x (LamVar y)= x==y
+free x (LamAbs y e) | x == y = False
+free x (LamAbs y e) | x /= y = free x e 
+free x (LamApp e1 e2) =(free x e1)||(free x e2)
+{- printing the expression -}
+printExp :: LamExpr -> String
+
+printExp (LamVar n) = "x" ++ show n
+printExp (LamApp (LamAbs x y) z) = "(" ++ printExp (LamAbs x y) ++ ")" ++  printExp z
+printExp (LamApp x  (LamApp e1 e2)) =   printExp x ++ "(" ++ printExp e1 ++ printExp e2 ++ ")"
+printExp (LamApp (LamVar n) x) = "x" ++ show n ++ printExp x 
+printExp (LamApp x (LamVar n) ) = printExp x ++ "x" ++ show n 
+
+
+printExp (LamAbs n x) = "\\x" ++ show n ++ "->" ++ printExp x
+
+
+
+-- Challenge 4 
+-- Parsing Arithmetic Expressions
+
+data ArithExpr = Add ArithExpr ArithExpr | Mul ArithExpr ArithExpr 
+               | Section ArithExpr  | SecApp ArithExpr ArithExpr | ArithNum Int
+    deriving (Show,Eq,Read) 
+
+parseArith :: String -> Maybe ArithExpr
+parseArith x   = maybeArith (parse expr x)
+
+maybeArith [(x,[])] = Just x
+maybeArith [] = Nothing
+maybeArith [(x,xs)] = Nothing
+
+
+--code taken from lectures and changed a little 
+expr :: Parser ArithExpr 
+expr =  do space
+           t <- term
+           space 
+           char '*'
+           space
+           e <- expr
+           space
+           return (Mul t  e)
+        <|> term
+ 
+term :: Parser ArithExpr 
+term =  do space
+           f  <- factor
+           space
+           char '+'
+           space
+           t  <- term
+           space
+           return (Add f t)
+        <|> factor
+
+ 
+factor :: Parser ArithExpr
+factor  = nat' <|> do space
+                      char '('
+                      space
+                      char '+'
+                      space
+                      x <- expr
+                      space
+                      char ')'
+                      space
+                      e <- factor
+                      space
+                      return (SecApp (Section x) e)                 
+                   <|> do space
+                          char '('
+                          space
+                          e <- expr
+                          space
+                          char ')'
+                          space
+                          return ( e) 
+
+
+                       
+   
+ 
+nat' :: Parser ArithExpr
+nat' = do ds <- some digit
+          return (ArithNum (read  ds))
+
+
+
+
+-- Challenge 5
+-- Church Encoding of arithmetic 
+
+churchEnc :: ArithExpr -> LamExpr 
+churchEnc (ArithNum n) | n < 0 = error " no negative numbers "
+                       | otherwise = LamAbs 0 (LamAbs 1(createNum n))
+churchEnc (Add x y) = LamApp (LamApp plus (churchEnc x)) (churchEnc y)
+churchEnc (Mul x y) = LamApp (LamApp mult (churchEnc x)) (churchEnc y) 
+churchEnc (SecApp (Section x) y) = LamApp (LamApp plus (churchEnc x)) (churchEnc y)
+
+
+createNum :: Int -> LamExpr
+
+createNum 0 = LamVar 1
+createNum n = LamApp (LamVar 0) (createNum (n-1)) 
+
+mult = LamAbs 0 (LamAbs 1 ( LamAbs 2 ( LamAbs 3 ( LamApp (LamApp (LamVar 0) (LamApp  (LamVar 1) (LamVar 2))) (LamVar 3)))))
+plus = LamAbs 0 (LamAbs 1 ( LamAbs 2 ( LamAbs 3 ( LamApp ( LamApp (LamVar 0 ) (LamVar 2 ) ) ( LamApp (LamApp (LamVar 1) (LamVar 2)) ( LamVar 3))))))
+-- Challenge 6
+-- Compare Innermost Reduction for Arithmetic and its Church Encoding
+
+innerRedn1 :: LamExpr -> Maybe LamExpr
+innerRedn1 (LamVar n) = Nothing
+
+innerRedn1 e1 | e1 == (eval1cbv e1) = Nothing
+              | otherwise = Just (eval1cbv e1)
+
+
+-- code taken from lectures 38 and 39 adn changed a bit 
+eval1cbv (LamVar x ) = (LamVar x)
+eval1cbv (LamAbs x e) | (checkinnerReduction e) == True = LamAbs x (eval1cbv e)
+                      | otherwise = (LamAbs x e)
+eval1cbv (LamApp (LamAbs x e1) e) | (checkinnerReduction e1) == False = subst e1 x e
+                                                | otherwise = LamApp (LamAbs x (eval1cbv e1)) e
+
+
+eval1cbv (LamApp e1@(LamVar x) e2) = LamApp e1 (eval1cbv e2)
+eval1cbv (LamApp e1 e2) = LamApp (eval1cbv e1) e2
+
+
+checkinnerReduction :: LamExpr -> Bool
+checkinnerReduction (LamVar x) = False
+checkinnerReduction (LamAbs x e1) = checkinnerReduction e1
+checkinnerReduction (LamApp (LamAbs x e) e1) = True 
+checkinnerReduction (LamApp e1 e2 ) = checkinnerReduction e1 || checkinnerReduction e2
+
+subst :: LamExpr -> Int -> LamExpr -> LamExpr
+subst (LamVar x) y e | x == y = e
+                     | x /= y = LamVar x
+
+subst (LamAbs x e1) y e | x /= y && not (free x e) = LamAbs x (subst e1 y e)
+                        | x /=y && (free x e) = let x' = (rename x e1) in
+                                           subst (LamAbs x' (subst e1 x (LamVar x'))) y e
+                        | x == y = LamAbs x e1
+subst (LamApp e1 e2) y e = LamApp (subst e1 y e) (subst e2 y e)
+rename x e | free (x + 1) e = rename (x + 1) e
+           | otherwise = (x+1)
+innerArithRedn1 :: ArithExpr -> Maybe ArithExpr
+innerArithRedn1 (ArithNum x) = Nothing 
+innerArithRedn1 e1 | e1 == reductionArith e1 = Nothing
+                   | otherwise = Just (reductionArith e1)
+
+
+
+reductionArith (Mul (ArithNum n) (ArithNum m)) =  ArithNum (n*m)
+reductionArith (Add (ArithNum n) (ArithNum m)) =  ArithNum (n+m)
+reductionArith (SecApp (Section(ArithNum n)) (ArithNum m)) = ArithNum (n+m)
+reductionArith (Mul x@(ArithNum y) e1) =  (Mul x (reductionArith e1))
+reductionArith (Add x@(ArithNum y) e1) =  (Add x (reductionArith e1)) 
+reductionArith (SecApp (Section (ArithNum n)) e2) = (SecApp (Section (ArithNum n)) (reductionArith e2))
+reductionArith (SecApp (Section e1) e2) =  (SecApp (Section (reductionArith e1)) e2)
+
+reductionArith (Mul e1 e2) = (Mul (reductionArith e1) e2)
+reductionArith (Add e1 e2) =  (Add (reductionArith e1) e2)
+
+
+compareArithLam :: ArithExpr -> (Int,Int)
+compareArithLam e1 = (evalArithm  e1 0, evalLambda (churchEnc e1) 0)
+
+
+
+evalArithm e1 z | (innerArithRedn1 e1) == Nothing = z
+                | otherwise = evalArithm (fromJust (innerArithRedn1 e1)) (z+1)
+                    
+evalLambda e1 z  | (innerRedn1 e1) == Nothing  = z                
+                 | otherwise = evalLambda (fromJust (innerRedn1 e1))  (z+1)
+                                     
+
+