Last active
December 3, 2020 04:05
-
-
Save ninokierulf/75ebea9dceed2718beb5f969d455e56a to your computer and use it in GitHub Desktop.
SLU 2010 Among Us Source Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class AmongUsGame { | |
init(players: [Player]) { | |
self.players = players | |
listenToPlayerEvents() | |
} | |
func start() { | |
assignTasks() | |
} | |
private func listenToPlayerEvents() { | |
for player in players { | |
player.onReport = { [weak self] deadBody, reporter in | |
self?.conductMeeting( | |
reason: MeetingReason.foundDeadBody(player: deadBody), | |
invoker: reporter, | |
onEnd: { playerActions in | |
self.actOnMeetingResult(meetingPlayerActions: playerActions) | |
}) | |
} | |
player.onPressEmergencyButton = { [weak self] buttonPresser in | |
self?.conductMeeting( | |
reason: MeetingReason.emergency, | |
invoker: buttonPresser, | |
onEnd: { playerActions in | |
self.actOnMeetingResult(meetingPlayerActions: playerActions) | |
}) | |
} | |
} | |
} | |
private func assignTasks() { | |
let commonTasksCount = 1 | |
let shortTasksCount = 5 | |
let longTasksCount = 1 | |
let commonTaskStore: [CommonTask] = [ | |
SwipeCardTask() | |
] | |
let shortTaskStore: [ShortTask] = [ | |
FixWiresTask() | |
] | |
let longTaskStore: [LongTask] = [ | |
ShootAsteriodsTask(), | |
DowloadUploadTask(), | |
MedScanTask() | |
] | |
for player in players { | |
player.accept(tasks: | |
commonTaskStore.random(commonTasksCount) | |
+ shortTaskStore.random(shortTasksCount) | |
+ longTaskStore.random(longTasksCount)) | |
} | |
} | |
private func conductMeeting(reason: MeetingReason, invoker: Player, onEnd: ([MeetingAction]) -> Void) { | |
let context = MeetingContext( | |
reason: reason, | |
invoker: invoker, | |
players: players) | |
var playerActions: [MeetingAction] = [] | |
for player in players { | |
playerActions.append(player.meetingDecision(context: context)) | |
} | |
onEnd(playerActions) | |
} | |
private func actOnMeetingResult(meetingPlayerActions meetingAction: [MeetingAction]) { | |
var ejectVoteMap: [String : Int] = [:] | |
var skipCount: Int = 0 | |
var noActionCount: Int = 0 | |
for action in meetingAction { | |
switch action { | |
case .noAction: noActionCount++ | |
case .skip: skipCount++ | |
case .eject(let player): | |
var count: Int = ejectVoteMap[player.name] ?? 0 | |
ejectVoteMap[player.name] = count++ | |
} | |
} | |
var highestEjectVoteCount: Int = 0 | |
for (playerName, voteCount) in ejectVoteMap.enumerated() { | |
if voteCount > highestEjectVoteCount { | |
highestEjectVoteCount = voteCount | |
} | |
} | |
var playersWithHighestEjectVoteCount: [Player] = ejectVoteMap | |
.filter( where: { _, voteCount in | |
voteCount == highestEjectVoteCount | |
}) | |
if playersWithHighestEjectVoteCount.count == 1, | |
skipCount < highestEjectVoteCount { | |
eject(playersWithHighestEjectVoteCount[0]) | |
} | |
else { | |
print("No one was ejected") | |
} | |
} | |
private func eject(player: Player) { | |
print("Ejected \(player.name)") | |
} | |
private let players: [Player] | |
enum MeetingReason { | |
case emergency | |
case foundDeadBody(player: Player) | |
} | |
enum MeetingAction { | |
case noAction | |
case skip | |
case eject(Player) | |
} | |
struct MeetingContext { | |
var reason: MeetingReason | |
var invoker: Player | |
var players: [Player] | |
} | |
class Player { | |
enum Role { | |
case crew | |
case impostor | |
} | |
enum State { | |
case alive | |
case dead | |
} | |
let name: String | |
let role: Role | |
var state: State = .alive | |
private var tasks: [Task] = [] | |
var onReport: (_ deadBody: Player, _ reporter: Player) -> Void = { _ in } | |
var onPressEmergencyButton: (_ buttonPresser: Player) -> Void = {} | |
init(name: String, role: Role) { | |
self.name = name | |
self.role = role | |
} | |
func accept(tasks: [Task]) { | |
self.tasks = tasks | |
} | |
func meetingDecision(context: MeetingContext) -> MeetingAction { | |
let inDoubt: Bool = true | |
if inDoubt { | |
return .eject(context.players.first( | |
where: { player in player.name == "randall" }) | |
?? Player.notFound) | |
} | |
else { | |
return MeetingAction.skip | |
} | |
} | |
private func report(deadBody: Player) { | |
onReport(deadBody, self) | |
} | |
private func pressEmergencyButton() { | |
onPressEmergencyButton(self) | |
} | |
static let notFound: Player = Player(name: "Ghost", role: .crew) | |
} | |
class Task {} | |
class CommonTask: Task {} | |
class ShortTask: Task {} | |
class LongTask: Task {} | |
class SwipeCardTask: CommonTask {} | |
class FixWiresTask: ShortTask {} | |
class ShootAsteriodsTask: LongTask {} | |
class DowloadUploadTask: LongTask {} | |
class MedScanTask: LongTask {} | |
} | |
class Main { | |
init() { | |
let game = AmongUsGame( | |
players: [ | |
AmongUsGame.Player(name: "Daisy", role: .crew), | |
AmongUsGame.Player(name: "randall", role: .crew), | |
AmongUsGame.Player(name: "puster", role: .crew), | |
AmongUsGame.Player(name: "Gutchi", role: .impostor), | |
AmongUsGame.Player(name: "Uldridge 1", role: .crew), | |
AmongUsGame.Player(name: "nino", role: .crew), | |
AmongUsGame.Player(name: "Chloe", role: .crew), | |
AmongUsGame.Player(name: "Myel", role: .crew), | |
AmongUsGame.Player(name: "BossJim", role: .crew), | |
AmongUsGame.Player(name: "Evita", role: .crew) | |
]) | |
game.start() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment