Skip to content

Commit 20f7b24

Browse files
Support AtCoderProblems (virtual contests)
1 parent 267d6ef commit 20f7b24

File tree

5 files changed

+27
-12
lines changed

5 files changed

+27
-12
lines changed

Sources/AtCoderCLI/main.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import SwiftShell
55
struct Command: ParsableCommand {
66
static var configuration = CommandConfiguration(
77
abstract: "AtCoder CLI for Swift.",
8-
version: "1.0.9",
8+
version: "1.0.10",
99
subcommands: [
1010
New.self,
1111
Submit.self,

Sources/AtCoderLibrary/API/OjApiCommand.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ import Foundation
22
import SwiftShell
33

44
enum OjApiCommand {
5-
static func getAllTasks(name: String, ojApiPath: String) throws -> (contest: Contest, problems: [Problem]) {
6-
let contest = try OjApiCommand.getContest(name: name, ojApiPath: ojApiPath)
5+
static func getAllTasks(url: String, ojApiPath: String) throws -> (contest: Contest, problems: [Problem]) {
6+
let contest = try OjApiCommand.getContest(url: url, ojApiPath: ojApiPath)
77
var problems = [Problem]()
88
let operation = BlockOperation()
99
var error: Error?
1010
contest.problems.forEach { problem in
1111
operation.addExecutionBlock {
1212
do {
13-
let problem = try OjApiCommand.getProblem(name: name, alphabet: problem.context.alphabet, url: problem.url, ojApiPath: ojApiPath)
13+
let problem = try OjApiCommand.getProblem(url: problem.url, ojApiPath: ojApiPath)
14+
.apply(context: problem.context)
1415
problems.append(problem)
1516
} catch(let e) {
1617
error = e
@@ -55,9 +56,9 @@ private extension OjApiCommand {
5556
}
5657
}
5758

58-
static func getContest(name: String, ojApiPath: String) throws -> Contest {
59+
static func getContest(url: String, ojApiPath: String) throws -> Contest {
5960
try precheck(path: ojApiPath)
60-
let result = run(ojApiPath, "get-contest", "https://atcoder.jp/contests/\(name)")
61+
let result = run(ojApiPath, "get-contest", url)
6162
guard result.succeeded else {
6263
throw result.stderror
6364
}
@@ -66,7 +67,7 @@ private extension OjApiCommand {
6667
return response.result
6768
}
6869

69-
static func getProblem(name: String, alphabet: String, url: URL, ojApiPath: String) throws -> Problem {
70+
static func getProblem(url: URL, ojApiPath: String) throws -> Problem {
7071
try precheck(path: ojApiPath)
7172
let result = run(ojApiPath, "get-problem", url.absoluteString)
7273
guard result.succeeded else {

Sources/AtCoderLibrary/API/Response.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ struct Problem: Decodable {
4242
let input: String
4343
let output: String
4444
}
45+
46+
func apply(context: Context) -> Self {
47+
.init(url: url, tests: tests, name: name, context: context, memoryLimit: memoryLimit, timeLimit: timeLimit)
48+
}
4549
}
4650

4751
struct Context: Decodable {

Sources/AtCoderLibrary/Command/New.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,21 @@ public struct New: ParsableCommand {
88
abstract: "Create a new contest project."
99
)
1010

11-
@Argument(help: "Name of the contest to create.\nex. \"abc111\"")
11+
@Argument(help: "Name of the contest to create.\nex. 'abc123'")
1212
var contestName: String
1313

14+
@Option(name: .shortAndLong, help: "Contest URL. \nIf no value is given, then 'https://atcoder.jp/contests/:contest_name' is used.")
15+
var contestUrl: String?
16+
1417
@Flag(name: .shortAndLong, help: "Open Package.swift after creation.")
1518
var open: Bool = false
1619

1720
@Option(help: "Specify the path to oj-api.")
1821
var ojApiPath: String = "oj-api"
1922

2023
public mutating func run() throws {
21-
let (contest, problems) = try OjApiCommand.getAllTasks(name: contestName, ojApiPath: ojApiPath)
24+
let contestUrl = self.contestUrl ?? "https://atcoder.jp/contests/\(contestName)"
25+
let (contest, problems) = try OjApiCommand.getAllTasks(url: contestUrl, ojApiPath: ojApiPath)
2226
try FileManager.default.createDirectory(atPath: contestName, withIntermediateDirectories: true)
2327
FileManager.default.changeCurrentDirectoryPath(contestName)
2428

Sources/AtCoderLibrary/Command/New/Generator/Test.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
struct Test: Generator {
22
let problem: Problem
3-
var className: String { "\(problem.context.alphabet)Tests" }
4-
var fileName: String { "\(className).swift" }
5-
var directory: String? { "Tests/\(className)" }
3+
var className: String {
4+
if Int(problem.context.alphabet) != nil {
5+
// [!] Class name can not start with a number.
6+
return "_\(problem.context.alphabet)Tests"
7+
}
8+
return "\(problem.context.alphabet)Tests"
9+
}
10+
var fileName: String { "\(problem.context.alphabet)Tests.swift" }
11+
var directory: String? { "Tests/\(problem.context.alphabet)Tests" }
612
var source: String {
713
"""
814
import XCTest

0 commit comments

Comments
 (0)