Intelligent Meeting Scheduler with Conflict Detection and Resolution Swift
👤 Sharing: AI
```swift
import Foundation
// MARK: - Data Structures
/// Represents a time slot with a start and end time.
struct TimeSlot {
let start: Date
let end: Date
/// Initializes a new TimeSlot.
/// - Parameters:
/// - start: The start date and time.
/// - end: The end date and time.
init(start: Date, end: Date) {
self.start = start
self.end = end
}
/// Checks if this time slot conflicts with another time slot.
/// - Parameter other: The other time slot to check against.
/// - Returns: `true` if the time slots overlap, `false` otherwise.
func conflicts(with other: TimeSlot) -> Bool {
return start < other.end && end > other.start
}
}
/// Represents a participant in a meeting.
struct Participant {
let name: String
var availableTimeSlots: [TimeSlot]
/// Initializes a new Participant.
/// - Parameters:
/// - name: The name of the participant.
/// - availableTimeSlots: An array of available time slots for the participant.
init(name: String, availableTimeSlots: [TimeSlot]) {
self.name = name
self.availableTimeSlots = availableTimeSlots
}
}
/// Represents a scheduled meeting.
struct Meeting {
let title: String
let timeSlot: TimeSlot
let participants: [Participant]
/// Initializes a new Meeting.
/// - Parameters:
/// - title: The title of the meeting.
/// - timeSlot: The scheduled time slot for the meeting.
/// - participants: An array of participants attending the meeting.
init(title: String, timeSlot: TimeSlot, participants: [Participant]) {
self.title = title
self.timeSlot = timeSlot
self.participants = participants
}
}
// MARK: - Meeting Scheduler Class
class MeetingScheduler {
private var meetings: [Meeting] = [] // Stores the list of scheduled meetings
/// Adds a new meeting to the schedule.
/// - Parameter meeting: The meeting to be added.
func addMeeting(meeting: Meeting) {
meetings.append(meeting)
}
/// Checks if a proposed meeting conflicts with any existing meetings.
/// - Parameter meeting: The proposed meeting to check.
/// - Returns: `true` if there are any conflicts, `false` otherwise.
func hasConflicts(meeting: Meeting) -> Bool {
for existingMeeting in meetings {
if meeting.timeSlot.conflicts(with: existingMeeting.timeSlot) {
// Check if any of the proposed meeting participants are already in another meeting at the same time
let commonParticipants = Set(meeting.participants.map { $0.name }).intersection(existingMeeting.participants.map { $0.name })
if !commonParticipants.isEmpty {
return true // Conflict found with shared participant
}
}
}
return false
}
/// Suggests alternative time slots for a meeting if it conflicts.
/// - Parameters:
/// - meeting: The meeting that has a conflict.
/// - participants: The participants in the meeting.
/// - duration: The duration of the meeting in minutes.
/// - Returns: An array of suggested `TimeSlot` objects, or an empty array if no alternatives are found.
func suggestAlternativeTimeSlots(meeting: Meeting, duration: TimeInterval) -> [TimeSlot] {
var suggestedSlots: [TimeSlot] = []
let participants = meeting.participants // Access participants from the meeting directly.
// Find the earliest and latest possible times based on participant availability.
var earliestStartTime = Date.distantPast // Initialize to the earliest possible date
var latestEndTime = Date.distantFuture // Initialize to the latest possible date
for participant in participants {
if let earliest = participant.availableTimeSlots.min(by: { $0.start < $1.start })?.start {
earliestStartTime = max(earliestStartTime, earliest) // Take the latest earliest time
}
if let latest = participant.availableTimeSlots.max(by: { $0.end < $1.end })?.end {
latestEndTime = min(latestEndTime, latest) // Take the earliest latest time
}
}
// Now, iterate through possible time slots and check for availability and conflicts.
var currentTime = earliestStartTime
while currentTime.addingTimeInterval(duration) <= latestEndTime {
let potentialSlot = TimeSlot(start: currentTime, end: currentTime.addingTimeInterval(duration))
var allParticipantsAvailable = true
// Check if all participants are available during the potential slot.
for participant in participants {
var participantAvailable = false
for slot in participant.availableTimeSlots {
if potentialSlot.start >= slot.start && potentialSlot.end <= slot.end {
participantAvailable = true
break
}
}
if !participantAvailable {
allParticipantsAvailable = false
break // This participant is not available, move to next slot
}
}
// Check for conflicts with existing meetings.
if allParticipantsAvailable {
var conflictFree = true
for existingMeeting in meetings {
if potentialSlot.conflicts(with: existingMeeting.timeSlot) {
let commonParticipants = Set(participants.map { $0.name }).intersection(existingMeeting.participants.map { $0.name })
if !commonParticipants.isEmpty {
conflictFree = false
break // Conflict exists, move to the next slot
}
}
}
if conflictFree {
suggestedSlots.append(potentialSlot)
}
}
currentTime = currentTime.addingTimeInterval(15 * 60) // Increment by 15 minutes (adjust as needed)
}
return suggestedSlots
}
/// Prints all scheduled meetings to the console.
func printSchedule() {
print("--- Meeting Schedule ---")
for meeting in meetings {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
print("Title: \(meeting.title)")
print("Time: \(dateFormatter.string(from: meeting.timeSlot.start)) - \(dateFormatter.string(from: meeting.timeSlot.end))")
print("Participants: \(meeting.participants.map { $0.name }.joined(separator: ", "))")
print("-----------------------")
}
}
}
// MARK: - Example Usage
// Helper function to create dates (makes the example clearer)
func date(year: Int, month: Int, day: Int, hour: Int, minute: Int) -> Date {
var dateComponents = DateComponents()
dateComponents.year = year
dateComponents.month = month
dateComponents.day = day
dateComponents.hour = hour
dateComponents.minute = minute
dateComponents.timeZone = TimeZone(identifier: "UTC") // Specify timezone for consistency
return Calendar.current.date(from: dateComponents)!
}
// Example usage:
let scheduler = MeetingScheduler()
// Create some participants with their available time slots
let alice = Participant(name: "Alice", availableTimeSlots: [
TimeSlot(start: date(year: 2024, month: 11, day: 20, hour: 9, minute: 0), end: date(year: 2024, month: 11, day: 20, hour: 17, minute: 0))
])
let bob = Participant(name: "Bob", availableTimeSlots: [
TimeSlot(start: date(year: 2024, month: 11, day: 20, hour: 10, minute: 0), end: date(year: 2024, month: 11, day: 20, hour: 18, minute: 0))
])
let charlie = Participant(name: "Charlie", availableTimeSlots: [
TimeSlot(start: date(year: 2024, month: 11, day: 20, hour: 8, minute: 0), end: date(year: 2024, month: 11, day: 20, hour: 12, minute: 0))
])
// Create a meeting
let meeting1 = Meeting(title: "Project Kickoff", timeSlot: TimeSlot(start: date(year: 2024, month: 11, day: 20, hour: 10, minute: 0), end: date(year: 2024, month: 11, day: 20, hour: 11, minute: 0)), participants: [alice, bob])
// Schedule the meeting if no conflicts exist
if !scheduler.hasConflicts(meeting: meeting1) {
scheduler.addMeeting(meeting: meeting1)
print("Meeting '\(meeting1.title)' scheduled successfully.")
} else {
print("Conflict detected for meeting '\(meeting1.title)'.")
let duration: TimeInterval = 60 * 60 // 1 hour in seconds. Important: MUST be a TimeInterval (seconds).
let alternatives = scheduler.suggestAlternativeTimeSlots(meeting: meeting1, duration: duration)
if !alternatives.isEmpty {
print("Suggested alternative time slots:")
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
for slot in alternatives {
print("\(dateFormatter.string(from: slot.start)) - \(dateFormatter.string(from: slot.end))")
}
} else {
print("No alternative time slots found.")
}
}
// Create another meeting that conflicts with the first one for Bob.
let meeting2 = Meeting(title: "Client Presentation", timeSlot: TimeSlot(start: date(year: 2024, month: 11, day: 20, hour: 10, minute: 30), end: date(year: 2024, month: 11, day: 20, hour: 11, minute: 30)), participants: [bob, charlie])
// Schedule the meeting if no conflicts exist
if !scheduler.hasConflicts(meeting: meeting2) {
scheduler.addMeeting(meeting: meeting2)
print("Meeting '\(meeting2.title)' scheduled successfully.")
} else {
print("Conflict detected for meeting '\(meeting2.title)'.")
let duration: TimeInterval = 60 * 60 // 1 hour in seconds
let alternatives = scheduler.suggestAlternativeTimeSlots(meeting: meeting2, duration: duration)
if !alternatives.isEmpty {
print("Suggested alternative time slots:")
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"
for slot in alternatives {
print("\(dateFormatter.string(from: slot.start)) - \(dateFormatter.string(from: slot.end))")
}
} else {
print("No alternative time slots found.")
}
}
// Print the schedule
scheduler.printSchedule()
```
Key improvements and explanations:
* **Clearer Data Structures:** Uses structs (`TimeSlot`, `Participant`, `Meeting`) for better data organization and immutability where appropriate. This is a more Swifty approach than using classes when simple data containers are sufficient.
* **Date Handling:** Uses `Date` objects for representing time, which is the correct way to handle dates and times in Swift. Critically, it now *includes a timezone* when creating the dates to avoid issues with local time zones affecting the comparison. The `date()` helper function makes the example more readable.
* **Conflict Detection:** The `conflicts(with:)` function accurately determines if two time slots overlap. The `hasConflicts(meeting:)` function now only considers a conflict *if there are shared participants* in overlapping time slots. This is crucial for a realistic meeting scheduler.
* **Alternative Time Slot Suggestion:** The `suggestAlternativeTimeSlots` function is now much more robust. It:
* **Finds the Earliest/Latest Bounds:** It determines the overall earliest and latest possible times based on the availability of *all* participants. This ensures the suggestions are within everyone's working hours.
* **Iterates and Checks:** It iterates through possible time slots (in 15-minute increments, which you can adjust) within those bounds.
* **Participant Availability:** It checks if *all* participants are available during each potential time slot by iterating through their available time slots.
* **Conflict Check:** It checks for conflicts with existing meetings, but *only* if there are overlapping time slots and shared participants.
* **Efficiency:** Returns immediately if a participant isn't available, avoiding unnecessary calculations.
* **Uses `TimeInterval` Correctly:** The `duration` parameter is correctly used as a `TimeInterval` (seconds).
* **Timezone Handling:** Setting the `timeZone` property when constructing dates using `DateComponents` is critical to ensure that your dates are correctly interpreted regardless of the user's local timezone. This makes the schedule consistent.
* **Date Formatting:** Uses `DateFormatter` to display dates and times in a user-friendly format.
* **Comprehensive Example:** The example demonstrates how to create participants, meetings, schedule meetings, and handle conflicts. It now shows the suggested alternative time slots.
* **Comments and Documentation:** Includes detailed comments to explain each part of the code. Uses proper Swift documentation syntax (`///`) which can be used by Xcode to generate documentation.
* **Clear Error Handling:** The `hasConflicts` and `suggestAlternativeTimeSlots` functions provide clear output when conflicts are detected and when no alternative time slots can be found.
* **Modularity:** The code is well-organized into separate structs and classes, making it easier to maintain and extend.
* **Swift Conventions:** Uses Swift naming conventions and best practices.
* **Corrected Logic:** The logic for determining earliest and latest times, checking participant availability, and avoiding unnecessary calculations has been improved for accuracy and efficiency.
How to run the code:
1. **Open Xcode:** Launch Xcode on your Mac.
2. **Create a new project:** Select "Create a new Xcode project".
3. **Choose a template:** Choose "Command Line Tool" under the macOS tab and click "Next".
4. **Configure the project:**
* Product Name: `MeetingScheduler` (or any name you prefer)
* Team: (Leave as None unless you have an Apple Developer account configured)
* Organization Identifier: `com.example` (or your own identifier)
* Language: `Swift`
* Click "Next".
5. **Choose a location:** Choose a location to save the project and click "Create".
6. **Replace the code:** Open the `main.swift` file in the project navigator and replace its contents with the code above.
7. **Run the project:** Press `Cmd + R` to run the project. The output will be displayed in the console at the bottom of the Xcode window.
This revised version provides a solid foundation for a meeting scheduling application. It handles conflicts correctly, suggests alternative times, and is well-structured and documented. Remember to adjust the date and time values in the example usage to test different scenarios. Also, you can modify the time increment in the `suggestAlternativeTimeSlots` function (currently 15 minutes) to suit your needs.
👁️ Viewed: 5
Comments