| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- using UnityEngine;
- using System.Collections.Generic;
- using System.Linq;
- public class HotelRatingSystem : MonoBehaviour
- {
- public static HotelRatingSystem Instance { get; private set; }
- [Header("Rating Components")]
- [SerializeField] private float baseRating = 3f;
- [SerializeField] private float currentOverallRating = 3f;
- [Header("Rating Weights")]
- [SerializeField] private float guestSatisfactionWeight = 0.4f;
- [SerializeField] private float facilityQualityWeight = 0.25f;
- [SerializeField] private float staffEfficiencyWeight = 0.15f;
- [SerializeField] private float roomQualityWeight = 0.1f;
- [SerializeField] private float serviceSpeedWeight = 0.1f;
- [Header("Rating History")]
- [SerializeField] private List<RatingSnapshot> ratingHistory = new List<RatingSnapshot>();
- [SerializeField] private int maxHistoryEntries = 100;
- private Dictionary<string, float> componentRatings = new Dictionary<string, float>();
- private float lastRatingUpdate = 0f;
- private float ratingUpdateInterval = 30f; // Update every 30 seconds
- // Events
- public System.Action<float, float> OnRatingChanged; // old rating, new rating
- public System.Action<RatingSnapshot> OnRatingUpdated;
- private void Awake()
- {
- if (Instance != null && Instance != this)
- {
- Destroy(this.gameObject);
- return;
- }
- Instance = this;
- }
- private void Start()
- {
- InitializeRatingSystem();
- }
- private void Update()
- {
- if (Time.time - lastRatingUpdate >= ratingUpdateInterval)
- {
- UpdateOverallRating();
- lastRatingUpdate = Time.time;
- }
- }
- #region Initialization
- private void InitializeRatingSystem()
- {
- componentRatings["GuestSatisfaction"] = 0.5f;
- componentRatings["FacilityQuality"] = 0.5f;
- componentRatings["StaffEfficiency"] = 0.5f;
- componentRatings["RoomQuality"] = 0.5f;
- componentRatings["ServiceSpeed"] = 0.5f;
- currentOverallRating = baseRating;
- Debug.Log("Hotel Rating System initialized");
- }
- #endregion
- #region Rating Calculation
- public void UpdateOverallRating()
- {
- float previousRating = currentOverallRating;
- // Calculate component ratings
- UpdateComponentRatings();
- // Calculate weighted overall rating
- float newRating = CalculateWeightedRating();
- // Apply some smoothing to prevent rapid changes
- currentOverallRating = Mathf.Lerp(currentOverallRating, newRating, 0.1f);
- currentOverallRating = Mathf.Clamp(currentOverallRating, 1f, 5f);
- // Create rating snapshot
- RatingSnapshot snapshot = CreateRatingSnapshot();
- AddRatingToHistory(snapshot);
- // Notify of rating change
- if (Mathf.Abs(previousRating - currentOverallRating) > 0.01f)
- {
- OnRatingChanged?.Invoke(previousRating, currentOverallRating);
- OnRatingUpdated?.Invoke(snapshot);
- Debug.Log($"Hotel rating updated: {previousRating:F2} → {currentOverallRating:F2}");
- }
- }
- private void UpdateComponentRatings()
- {
- // Guest Satisfaction
- componentRatings["GuestSatisfaction"] = CalculateGuestSatisfactionRating();
- // Facility Quality
- componentRatings["FacilityQuality"] = CalculateFacilityQualityRating();
- // Staff Efficiency
- componentRatings["StaffEfficiency"] = CalculateStaffEfficiencyRating();
- // Room Quality
- componentRatings["RoomQuality"] = CalculateRoomQualityRating();
- // Service Speed
- componentRatings["ServiceSpeed"] = CalculateServiceSpeedRating();
- }
- private float CalculateWeightedRating()
- {
- float weightedSum = 0f;
- float totalWeight = 0f;
- weightedSum += componentRatings["GuestSatisfaction"] * guestSatisfactionWeight;
- totalWeight += guestSatisfactionWeight;
- weightedSum += componentRatings["FacilityQuality"] * facilityQualityWeight;
- totalWeight += facilityQualityWeight;
- weightedSum += componentRatings["StaffEfficiency"] * staffEfficiencyWeight;
- totalWeight += staffEfficiencyWeight;
- weightedSum += componentRatings["RoomQuality"] * roomQualityWeight;
- totalWeight += roomQualityWeight;
- weightedSum += componentRatings["ServiceSpeed"] * serviceSpeedWeight;
- totalWeight += serviceSpeedWeight;
- // Convert from 0-1 scale to 1-5 star scale
- float normalizedRating = totalWeight > 0 ? weightedSum / totalWeight : 0.5f;
- return 1f + (normalizedRating * 4f);
- }
- #endregion
- #region Component Rating Calculations
- private float CalculateGuestSatisfactionRating()
- {
- if (HotelManager.Instance == null) return 0.5f;
- var currentGuests = HotelManager.Instance.GetCurrentGuests();
- if (currentGuests.Count == 0) return 0.5f;
- // Only count guests who have been assigned rooms
- var satisfiedGuests = currentGuests.Where(g => g.AssignedRoom != null).ToList();
- if (satisfiedGuests.Count == 0) return 0.5f;
- float totalSatisfaction = satisfiedGuests.Sum(g => g.SatisfactionLevel);
- return totalSatisfaction / satisfiedGuests.Count;
- }
- private float CalculateFacilityQualityRating()
- {
- if (FacilityManager.Instance == null) return 0.5f;
- var facilities = FacilityManager.Instance.GetAvailableFacilities();
- if (facilities.Count == 0) return 0.3f; // Low rating if no facilities
- float totalQuality = facilities.Sum(f => f.QualityRating);
- float averageQuality = totalQuality / facilities.Count;
- // Bonus for having diverse facilities
- var uniqueTypes = facilities.Select(f => f.Type).Distinct().Count();
- float diversityBonus = Mathf.Clamp01(uniqueTypes / 6f) * 0.2f; // Max 20% bonus for 6+ facility types
- return Mathf.Clamp01(averageQuality + diversityBonus);
- }
- private float CalculateStaffEfficiencyRating()
- {
- if (StaffManager.Instance == null) return 0.5f;
- float averageEfficiency = StaffManager.Instance.GetAverageStaffEfficiency();
- // Factor in staff-to-guest ratio
- int totalStaff = StaffManager.Instance.GetTotalStaffCount();
- int totalGuests = HotelManager.Instance?.GetTotalGuests() ?? 0;
- float idealRatio = 0.3f; // 3 staff per 10 guests
- float actualRatio = totalGuests > 0 ? (float)totalStaff / totalGuests : 1f;
- float ratioScore = Mathf.Clamp01(actualRatio / idealRatio);
- // Combine efficiency and ratio
- return (averageEfficiency * 0.7f) + (ratioScore * 0.3f);
- }
- private float CalculateRoomQualityRating()
- {
- if (HotelManager.Instance == null) return 0.5f;
- var allRooms = HotelManager.Instance.GetAllRooms();
- if (allRooms.Count == 0) return 0.2f;
- // For now, assume all rooms have base quality
- // This could be expanded to include room upgrades, cleanliness, etc.
- float baseRoomQuality = 0.6f;
- // Factor in room availability vs demand
- float occupancyRate = HotelManager.Instance.GetOccupancyRate();
- float availabilityBonus = occupancyRate < 0.9f ? 0.1f : 0f; // Bonus for having available rooms
- return Mathf.Clamp01(baseRoomQuality + availabilityBonus);
- }
- private float CalculateServiceSpeedRating()
- {
- if (StaffManager.Instance == null) return 0.5f;
- // Base this on average guest patience levels
- if (HotelManager.Instance == null) return 0.5f;
- var currentGuests = HotelManager.Instance.GetCurrentGuests();
- if (currentGuests.Count == 0) return 0.7f; // Good rating if no complaints
- // Calculate average patience (higher patience = better service speed)
- float totalPatience = currentGuests.Sum(g => g.Patience);
- float averagePatience = totalPatience / currentGuests.Count;
- return averagePatience / 100f; // Convert from 0-100 to 0-1 scale
- }
- #endregion
- #region Rating History
- private RatingSnapshot CreateRatingSnapshot()
- {
- return new RatingSnapshot
- {
- timestamp = System.DateTime.Now,
- overallRating = currentOverallRating,
- guestSatisfaction = componentRatings["GuestSatisfaction"],
- facilityQuality = componentRatings["FacilityQuality"],
- staffEfficiency = componentRatings["StaffEfficiency"],
- roomQuality = componentRatings["RoomQuality"],
- serviceSpeed = componentRatings["ServiceSpeed"],
- totalGuests = HotelManager.Instance?.GetTotalGuests() ?? 0,
- totalStaff = StaffManager.Instance?.GetTotalStaffCount() ?? 0,
- occupancyRate = HotelManager.Instance?.GetOccupancyRate() ?? 0f
- };
- }
- private void AddRatingToHistory(RatingSnapshot snapshot)
- {
- ratingHistory.Add(snapshot);
- // Limit history size
- if (ratingHistory.Count > maxHistoryEntries)
- {
- ratingHistory.RemoveAt(0);
- }
- }
- public List<RatingSnapshot> GetRatingHistory(int entryCount = 10)
- {
- int startIndex = Mathf.Max(0, ratingHistory.Count - entryCount);
- return ratingHistory.GetRange(startIndex, ratingHistory.Count - startIndex);
- }
- #endregion
- #region Public Interface
- public float GetOverallRating()
- {
- return currentOverallRating;
- }
- public string GetRatingStars()
- {
- int stars = Mathf.RoundToInt(currentOverallRating);
- return new string('★', stars) + new string('☆', 5 - stars);
- }
- public Dictionary<string, float> GetComponentRatings()
- {
- return new Dictionary<string, float>(componentRatings);
- }
- public string GetRatingCategory()
- {
- if (currentOverallRating >= 4.5f) return "Luxury";
- if (currentOverallRating >= 3.5f) return "Premium";
- if (currentOverallRating >= 2.5f) return "Standard";
- if (currentOverallRating >= 1.5f) return "Budget";
- return "Poor";
- }
- public float GetRatingChangeLastPeriod()
- {
- if (ratingHistory.Count < 2) return 0f;
- var latest = ratingHistory[ratingHistory.Count - 1];
- var previous = ratingHistory[ratingHistory.Count - 2];
- return latest.overallRating - previous.overallRating;
- }
- public void ForceRatingUpdate()
- {
- UpdateOverallRating();
- }
- #endregion
- #region Guest Attraction
- public Guest.GuestType GetAttractedGuestType()
- {
- // Higher rated hotels attract higher profile guests
- if (currentOverallRating >= 4.5f && UnityEngine.Random.value < 0.15f)
- return Guest.GuestType.Celebrity;
- if (currentOverallRating >= 4f && UnityEngine.Random.value < 0.25f)
- return Guest.GuestType.VIP;
- if (currentOverallRating >= 3.5f && UnityEngine.Random.value < 0.35f)
- return Guest.GuestType.Business;
- if (UnityEngine.Random.value < 0.4f)
- return Guest.GuestType.Family;
- return Guest.GuestType.Regular;
- }
- public float GetGuestArrivalRateMultiplier()
- {
- // Higher rated hotels get more guests
- return Mathf.Clamp(currentOverallRating / 3f, 0.5f, 2f);
- }
- #endregion
- }
- // Data structure for rating snapshots
- [System.Serializable]
- public class RatingSnapshot
- {
- public System.DateTime timestamp;
- public float overallRating;
- public float guestSatisfaction;
- public float facilityQuality;
- public float staffEfficiency;
- public float roomQuality;
- public float serviceSpeed;
- public int totalGuests;
- public int totalStaff;
- public float occupancyRate;
- public override string ToString()
- {
- return $"Rating: {overallRating:F2} stars at {timestamp:HH:mm:ss} " +
- $"(Guests: {totalGuests}, Staff: {totalStaff}, Occupancy: {occupancyRate:P0})";
- }
- }
|