I made my own script to filter problems in CF problemset. If such script with same function already exists you can ignore my post or downvote it.
This is a python 3 script that fetches all problems from CF problemset and allows custom filtering. It supports custom filter criteria in python expression format. After you input the filter function, it filters the problems and choose a random one. More details can be found in spoilers below.
In your filter expression, you are given variables problem
and contest
, and it's supposed to returns 1
if the problem matches your search, 0
otherwise.
Example: problem.rating == 2400 and "geometry" not in problem.tags and contest.divison == "Div. 1"
The variable problem
contains such properties:
id - The ID of the problem, in the format e.g. 1234H, 2024A.
rating - The CF rating tag. Can be absent.
contest - The contest id of this problem. Equals to contest.id.
psetname - The problemset name of this problem.
index - The problem index in its contest, such as A or C.
pts - The problem points worth in its contest, 1500 for example.
tags - Problem tags. Used to filter out 'data structure' or 'geometry'.
The variable contest
contains such properties:
id - The ID of the contest. It is different from the round number.
type - The scroing rules of such contest. Enumeration of "CF", "IOI" and "ICPC".
name - The contest name. Example, "Codeforces Round #7744 (Div. 10)".
division - The contest division in string. Enumeration of "Div. 1+Div. 2", "Div. 1", "Div. 2", "Div. 3", "Div. 4", "Educational" and "Unknown". (Wanna know how it works? Just do string matching in the contest name dummy)
Most of these properties are directly copied from the API.
import urllib.request as request
import json,random
class Problem:
def __init__(self, apiobj):
self.id = f"{apiobj['contestId']}{apiobj['index']}"
self.rating = apiobj['rating']
self.tags = apiobj['tags']
self.contest = apiobj['contestId']
self.psetname = apiobj['problemsetName']
self.index = apiobj['index']
self.pts = apiobj['points']
class Contest:
DIV_NAMES = ["Div. 1+Div. 2", "Div. 2", "Div. 1", "Educational", "Div. 3", "Div. 4"]
def __init__(self, apiobj):
self.id = apiobj['id']
self.type = apiobj['type']
self.name = apiobj['name']
self.division = "Unknown"
for div in Contest.DIV_NAMES:
if div in apiobj['name']:
self.division = div
break
contests = {}
problems = []
def strawberry(problem,contest): # A test filter function
return problem.rating == 2400 and contest.id >= 1000 and contest.division == "Div. 1" and "geometry" not in problem.tags
def fetchall():
global contests, problems
contests = {}
problems = []
try:
contests_raw = request.urlopen("http://codeforces.net/api/contest.list?gym=false").read().decode()
problems_raw = request.urlopen("http://codeforces.net/api/problemset.problems").read().decode()
except:
print("Codeforces API playing Genshin Impact at the moment")
return False
contests_obj = json.loads(contests_raw)
problems_obj = json.loads(problems_raw)
if contests_obj["status"] != "OK" or problems_obj["status"] != "OK":
print("Codeforces API thinks your skill is too mediocre to use it")
return False
for problem_obj in problems_obj["result"]["problems"]:
try:
problem = Problem(problem_obj)
problems.append(problem)
except:
pass
for contest_obj in contests_obj["result"]:
try:
contest = Contest(contest_obj)
contests[contest.id] = contest
except:
pass
return True
print("Fetching problems...")
if not fetchall():
exit(0)
candidates = []
schema = input("filter returns ")
for problem in problems:
if eval(schema,{'problem':problem,'contest':contests[problem.contest]}):
candidates.append(problem)
if not len(candidates):
print ("No problems matches your filter.")
else:
result = random.choice(candidates)
print(f"Your problem is: {result.id}")
...