Skip to content

Commit

Permalink
Support LeetCode contests
Browse files Browse the repository at this point in the history
  • Loading branch information
slycelote committed May 1, 2022
1 parent b3d0f34 commit 6df94ae
Show file tree
Hide file tree
Showing 26 changed files with 114 additions and 3 deletions.
1 change: 1 addition & 0 deletions libcaide/libcaide.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ library
Caide.Parsers.GCJ
Caide.Parsers.HackerRank
Caide.Parsers.LeetCode
Caide.Parsers.LeetCodeContest
Caide.Parsers.POJ
Caide.Parsers.RCC
Caide.Parsers.RccContest
Expand Down
6 changes: 3 additions & 3 deletions libcaide/src/Caide/Commands/ParseContest.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ module Caide.Commands.ParseContest(
) where

import Data.List (find)
import qualified Data.Text as T

import Caide.Types (CaideIO, throw)

import Caide.Parsers.Common (URL, ContestParser(..))
import Caide.Parsers.CodeforcesContest
import Caide.Parsers.CodeChefContest
import qualified Caide.Parsers.LeetCodeContest as LeetCode
import Caide.Parsers.RccContest

createContest :: URL -> CaideIO ()
createContest contestUrl = case findContestParser contestUrl of
Nothing -> throw . T.concat $ [contestUrl, " is not recognized as a supported contest URL"]
Nothing -> throw $ contestUrl <> " is not recognized as a supported contest URL"
Just contestParser -> contestParser `parseContest` contestUrl

contestParsers :: [ContestParser]
contestParsers = [codeforcesContestParser, codeChefContestParser, rccContestParser]
contestParsers = [codeforcesContestParser, codeChefContestParser, LeetCode.contestParser, rccContestParser]

findContestParser :: URL -> Maybe ContestParser
findContestParser url = find (`contestUrlMatches` url) contestParsers
Expand Down
62 changes: 62 additions & 0 deletions libcaide/src/Caide/Parsers/LeetCodeContest.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{-# LANGUAGE DeriveGeneric, NamedFieldPuns, OverloadedStrings #-}
module Caide.Parsers.LeetCodeContest(
contestParser
) where

import Control.Monad.Extended (liftIO)
import qualified Data.ByteString.Lazy as LBS
import Data.Either.Util (mapLeft)
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import Data.Text (Text)

import GHC.Generics (Generic)
import Network.URI (parseURI, pathSegments, URI(uriPath, uriQuery, uriFragment))

import qualified Data.Aeson as Aeson

import Caide.Commands.ParseProblem (parseProblems)
import Caide.Parsers.Common (URL, ContestParser(..), isHostOneOf)
import Caide.Types
import Caide.Util (downloadDocument, tshow)


isLeetCodeUrl :: URL -> Bool
isLeetCodeUrl = isHostOneOf ["leetcode.com", "www.leetcode.com", "leetcode-cn.com", "www.leetcode-cn.com"]


contestParser :: ContestParser
contestParser = ContestParser
{ contestUrlMatches = isLeetCodeUrl
, parseContest = doParseContest
}

newtype ProblemInContest = ProblemInContest { title_slug :: Text }
deriving (Show, Generic)
instance Aeson.FromJSON ProblemInContest

newtype Contest = Contest { questions :: [ProblemInContest] }
deriving (Show, Generic)
instance Aeson.FromJSON Contest


eitherDecodeText' :: Aeson.FromJSON a => Text -> Either Text a
eitherDecodeText' = mapLeft T.pack . Aeson.eitherDecode' . LBS.fromStrict . T.encodeUtf8

doParseContest :: URL -> CaideIO ()
doParseContest url = case (mbUri, mbPathSegments) of
(Just uri, Just seg) | length seg >= 2 && seg !! (length seg - 2) == "contest" -> do
let contestId = last seg
apiUri = uri{uriPath = "/contest/api/info/" <> contestId <> "/", uriQuery="", uriFragment=""}
probUrlPrefix = tshow $ apiUri{uriPath="/problems/"}
mbDoc <- liftIO $ downloadDocument $ tshow apiUri
case mbDoc >>= eitherDecodeText' of
Left err -> throw err
Right (Contest{questions}) -> parseProblems 3 $
[ probUrlPrefix <> (title_slug prob) | prob <- questions ]

_ -> throw "Invalid contest url"
where
mbUri = parseURI (T.unpack url)
mbPathSegments = pathSegments <$> mbUri

6 changes: 6 additions & 0 deletions libcaide/tests/leetcode-contest.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

basic_init
"$CAIDE" contest https://leetcode.com/contest/weekly-contest-291
compare_with after-parse {total-appeal-of-a-string,k-divisible-elements-subarrays,minimum-consecutive-cards-to-pick-up,remove-digit-from-number-to-maximize-result}/{problem.ini,case{1,2}.{in,out}}

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
11
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[1,2,3,4]
4
1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
10
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[problem]
double_precision: 0.000001
name: K Divisible Elements Subarrays
type: leetcode,countDistinct:int,nums:vint,k:int,p:int

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[3,4,2,3,4,7]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[1,0,5,3]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[problem]
double_precision: 0.000001
name: Minimum Consecutive Cards to Pick Up
type: leetcode,minimumCardPickup:int,cards:vint

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"123"
"3"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"12"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"1231"
"1"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"231"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"551"
"5"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"51"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[problem]
double_precision: 0.000001
name: Remove Digit From Number to Maximize Result
type: leetcode,removeDigit:String,number:String,digit:character

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"abbca"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
28
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"code"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[problem]
double_precision: 0.000001
name: Total Appeal of A String
type: leetcode,appealSum:long,s:String

0 comments on commit 6df94ae

Please sign in to comment.