-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmeow.swift
More file actions
243 lines (201 loc) · 7.86 KB
/
Copy pathmeow.swift
File metadata and controls
243 lines (201 loc) · 7.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#!/usr/bin/env swift
//
// MEOW Engine — Swift version
// Transpiled from Python, runs gladiators via subprocess
//
import Foundation
struct Gladiator: Codable {
let language: String
let cmd: [String]
let disciplines: [String]
let arenas: [String]
let root: String
}
struct ArenaPolicy: Codable {
let name: String
let validators: Int
let consensus: String
let adversarial: Bool
let scoring: String
}
struct GladiatorResult: Codable {
let gladiator: String
let arena: String
let ok: Bool
let output: String
let score: Double?
}
struct TournamentResult: Codable {
let cat: String
let results: [GladiatorResult]
}
func loadPolicy(name: String) throws -> ArenaPolicy {
let arenasDir = URL(fileURLWithPath: #file).deletingLastPathComponent().deletingLastPathComponent().appendingPathComponent("arenas")
let defaultData = try Data(contentsOf: arenasDir.appendingPathComponent("default.yaml"))
let defaultDict = try YAMLDecoder().decode([String: Any].self, from: defaultData)
var policyDict = defaultDict
let specificURL = arenasDir.appendingPathComponent("\(name).yaml")
if FileManager.default.fileExists(atPath: specificURL.path) {
let specificData = try Data(contentsOf: specificURL)
let specificDict = try YAMLDecoder().decode([String: Any].self, from: specificData)
policyDict.merge(specificDict) { _, new in new }
}
return ArenaPolicy(
name: name,
validators: policyDict["validators"] as? Int ?? 3,
consensus: policyDict["consensus"] as? String ?? "majority",
adversarial: policyDict["adversarial"] as? Bool ?? false,
scoring: policyDict["scoring"] as? String ?? "accuracy"
)
}
func discoverGladiators(languagesDir: String) -> [Gladiator] {
let base = URL(fileURLWithPath: languagesDir)
let enumerator = FileManager.default.enumerator(at: base, includingPropertiesForKeys: [.isDirectoryKey])!
var gladiators: [Gladiator] = []
for case let fileURL as URL in enumerator {
if fileURL.lastPathComponent == "contract.json" {
let data = try! Data(contentsOf: fileURL)
let contract = try! JSONDecoder().decode(Contract.self, from: data)
let root = fileURL.deletingLastPathComponent()
var cmd = contract.runtime.cmd
cmd = cmd.map { $0.replacingOccurrences(of: "{root}", with: root.path) }
let gladiator = Gladiator(
language: contract.language,
cmd: cmd,
disciplines: contract.disciplines,
arenas: contract.arenas,
root: root.path
)
gladiators.append(gladiator)
}
}
return gladiators.sorted { $0.language < $1.language }
}
struct Contract: Codable {
let language: String
let runtime: Runtime
let disciplines: [String]
let arenas: [String]
}
struct Runtime: Codable {
let cmd: [String]
let native: Bool
}
func runArena(arena: String, gladiators: [Gladiator]) -> [GladiatorResult] {
let policy = try! loadPolicy(name: arena)
let convoked = gladiators.filter { $0.disciplines.contains("construct") && $0.arenas.contains(arena) }
var results: [GladiatorResult] = []
for gladiator in convoked {
let process = Process()
process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
process.arguments = gladiator.cmd
let inputPipe = Pipe()
let outputPipe = Pipe()
process.standardInput = inputPipe
process.standardOutput = outputPipe
let request = ["discipline": "construct", "arena": arena]
let inputData = try! JSONEncoder().encode(request)
try! process.run()
inputPipe.fileHandleForWriting.write(inputData)
inputPipe.fileHandleForWriting.closeFile()
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
process.waitUntilExit()
let output = String(data: outputData, encoding: .utf8) ?? ""
let result = try! JSONDecoder().decode(GladiatorResult.self, from: outputData)
results.append(GladiatorResult(
gladiator: gladiator.language,
arena: arena,
ok: result.ok,
output: result.output,
score: result.score
))
}
return results
}
func runTournament() -> TournamentResult {
let gladiators = discoverGladiators(languagesDir: "../languages")
let arenas = ["ears", "cheeks", "padding", "whiskers", "eyes", "mouth", "nose", "geometry", "head_top"]
var allResults: [GladiatorResult] = []
for arena in arenas {
let results = runArena(arena: arena, gladiators: gladiators)
allResults.append(contentsOf: results)
}
// Build cat ASCII
let cat = """
|\\ _,,,---,,_
ZZZzz /,`.-'`' -. ;-;;,_
|,4- ) )-,_. ,\\ ( `'-'
'---''(_/--' `-'\\_)
"""
return TournamentResult(cat: cat, results: allResults)
}
@main
struct MEOW {
static func main() {
let args = CommandLine.arguments
if args.contains("--list-gladiators") {
let gladiators = discoverGladiators(languagesDir: "../languages")
for g in gladiators {
print("\(g.language.padding(toLength: 12, withPad: " ", startingAt: 0)) \(g.disciplines.joined(separator: ",").padding(toLength: 24, withPad: " ", startingAt: 0)) \(g.arenas.joined(separator: ","))")
}
exit(0)
}
if let idx = args.firstIndex(of: "--arena"), idx + 1 < args.count {
let arena = args[idx + 1]
let gladiators = discoverGladiators(languagesDir: "../languages")
let results = runArena(arena: arena, gladiators: gladiators)
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
let data = try! JSONEncoder().encode(results)
print(String(data: data, encoding: .utf8)!)
exit(0)
}
if args.contains("--tournament") {
let result = runTournament()
print(result.cat)
print("🏆 Tournament complete!")
exit(0)
}
if args.contains("--judge") {
let result = runTournament()
// Print mutations
exit(0)
}
if args.contains("--caesar") {
print("Et tu, Brute?")
exit(0)
}
print("Usage: meow --list-gladiators | --arena NAME | --tournament | --judge | --caesar")
exit(1)
}
}
// Simple YAML decoder for policy files
struct YAMLDecoder {
func decode(_ type: [String: Any].Type, from data: Data) throws -> [String: Any] {
let string = String(data: data, encoding: .utf8)!
var result: [String: Any] = [:]
for line in string.split(separator: "\n") {
let trimmed = line.trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed.isEmpty || trimmed.hasPrefix("#") { continue }
if let colonIndex = trimmed.firstIndex(of: ":") {
let key = String(trimmed[..<colonIndex]).trimmingCharacters(in: .whitespaces)
let value = String(trimmed[trimmed.index(after: colonIndex)...]).trimmingCharacters(in: .whitespaces)
if let intVal = Int(value) {
result[key] = intVal
} else if let boolVal = Bool(value) {
result[key] = boolVal
} else {
result[key] = value
}
}
}
return result
}
}
extension Bool {
init?(_ string: String) {
if string == "true" { self = true }
else if string == "false" { self = false }
else { return nil }
}
}