Imagine a weather dashboard asking for the same city every few seconds. Calling the real weather service every time would be wasteful, so we place a caching proxy in front of it. The proxy exposes the same operation as the real service, but it can reuse a recent reading instead of making another expensive call.
Time is measured in ticks and moves only when a test advances it.
The real service is deterministic. For a city, let base be 10 + (sum of the character codes in the name) % 21. The first fetch of that city returns "<city>: <base>C", and each later fetch of the same city adds 5 to the reading. So London reads London: 19C the first time it is fetched and London: 24C the second time.
The starter code already includes WeatherService, RealWeatherService, CacheEntry, and a ProxyDriver test harness. Your only task is to implement the CachingWeatherProxy class and make it collaborate with those provided types.
CachingWeatherProxy must support the following operations:
CachingWeatherProxy() creates a proxy wrapping a fresh weather service, with an empty cache and the clock at tick 0.String getTemperature(String city) returns the reading for that city, from the cache when the entry is still current and from the real service otherwise.int advanceTime(int ticks) moves the clock forward and returns the new tick.String lastLog() describes the most recent getTemperature call, or "NONE" before the first one.int serviceCallCount() returns how many fetches the real service actually performed.int freshCount() returns how many cached entries are still current at the current tick.boolean invalidate(String city) drops that city's entry and returns true, or returns false when there was nothing to drop.An entry stored at tick s is current while now - s is below 5, and has expired once now - s reaches 5. A fetch always stores its result with the current tick, so a refetched entry starts ageing again from zero.
lastLog takes one of three shapes:
"Cache MISS for <city>" when no entry was held."Cache HIT for <city> (age: <n>)" when a current entry was returned, where n is now - s."Cache EXPIRED for <city> (age: <n>)" when an entry was held but had aged out.You do not need to modify or recreate the supporting types. A genuine cache hit must return the stored value without touching RealWeatherService. The examples use ProxyDriver operations because it is the public test harness; your code changes belong only inside CachingWeatherProxy.
Input:
Output:
Explanation: The first call misses and consults the real service. The second call is served from the cache, so the service call count stays at 1.
Input:
Output:
Explanation: At age 4 the entry is still inside its 5 tick lifetime, so the cached reading comes back untouched. At age 5 it has expired, the real service is consulted again, and the fresh reading differs from the one that was cached.
1 <= city.length <= 200 <= ticks <= 100100 calls in total are made across all methods.Only CachingWeatherProxy is unfinished. The supporting types and ProxyDriver test harness are pre-implemented; do not modify them.
Full marks when a cached reading is returned without calling the real service, so `serviceCallCount` is unchanged across a hit and moves on every miss and every expiry. Lose points heavily when the proxy reports a hit after fetching anyway, or when it computes the reading itself instead of delegating.
Full marks when an entry whose age has reached 5 is treated as a miss, the refetched value replaces the old one, and the entry is stamped with the tick it was refetched at so its age restarts. Lose points when the lifetime is ignored, when age 5 still counts as fresh, or when the original stamp survives a refetch.
Full marks when each city has its own entry, `lastLog` reads `Cache MISS for <city>`, `Cache HIT for <city> (age: <n>)` or `Cache EXPIRED for <city> (age: <n>)` with the age measured from the stamp, `lastLog` is `NONE` before any lookup, and `invalidate` returns `false` for a city with no entry. Lose points for printing to stdout.
Passing every test is not enough on its own. A submission is accepted only when the design also clears the bar.
| Call | Returns |
|---|---|
| new ProxyDriver() | null |
| getTemperature("London") | "London: 19C" |
| lastLog() | "Cache MISS for London" |
| getTemperature("London") | "London: 19C" |
| lastLog() | "Cache HIT for London (age: 0)" |
| serviceCallCount() | 1 |
The first call misses and consults the real service. The second call is served from the cache, so the service call count stays at 1.
Run checks these cases. Submit also runs a larger hidden set.

