feat(daily): pure 7-day login-calendar logic + reward table
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
// lib/game/daily/daily_reward.dart
|
||||
import '../models/booster.dart';
|
||||
|
||||
/// The result of evaluating the calendar for "today".
|
||||
class DailyResolution {
|
||||
const DailyResolution({required this.claimable, required this.day});
|
||||
final bool claimable;
|
||||
final int day; // 1..7, the day to show/grant
|
||||
}
|
||||
|
||||
/// Pure 7-day login-calendar logic. No storage or clock — callers pass the
|
||||
/// persisted state and today's date so it is fully unit-testable.
|
||||
class DailyRewardCalendar {
|
||||
const DailyRewardCalendar();
|
||||
|
||||
static const int cycle = 7;
|
||||
|
||||
String ymd(DateTime date) {
|
||||
final m = date.month.toString().padLeft(2, '0');
|
||||
final d = date.day.toString().padLeft(2, '0');
|
||||
return '${date.year}-$m-$d';
|
||||
}
|
||||
|
||||
DailyResolution resolve({
|
||||
required String? lastClaimedYmd,
|
||||
required int storedDay,
|
||||
required DateTime today,
|
||||
}) {
|
||||
final todayYmd = ymd(today);
|
||||
if (lastClaimedYmd == todayYmd) {
|
||||
return DailyResolution(claimable: false, day: storedDay);
|
||||
}
|
||||
final yesterday = ymd(today.subtract(const Duration(days: 1)));
|
||||
final int day;
|
||||
if (lastClaimedYmd == yesterday) {
|
||||
day = (storedDay % cycle) + 1; // advance, wrapping 7 -> 1
|
||||
} else {
|
||||
day = 1; // first ever, or a day was missed
|
||||
}
|
||||
return DailyResolution(claimable: true, day: day);
|
||||
}
|
||||
|
||||
/// Boosters granted for a given calendar day (1..7). Tunable.
|
||||
Map<BoosterType, int> rewardFor(int day) {
|
||||
switch (day) {
|
||||
case 1:
|
||||
return {BoosterType.hammer: 1};
|
||||
case 2:
|
||||
return {BoosterType.shuffle: 1};
|
||||
case 3:
|
||||
return {BoosterType.lineBomb: 1};
|
||||
case 4:
|
||||
return {BoosterType.hammer: 1, BoosterType.shuffle: 1};
|
||||
case 5:
|
||||
return {BoosterType.shuffle: 1, BoosterType.lineBomb: 1};
|
||||
case 6:
|
||||
return {BoosterType.hammer: 1, BoosterType.lineBomb: 1};
|
||||
case 7:
|
||||
default:
|
||||
return {
|
||||
BoosterType.hammer: 2,
|
||||
BoosterType.shuffle: 2,
|
||||
BoosterType.lineBomb: 2,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'package:block_seasons/game/daily/daily_reward.dart';
|
||||
import 'package:block_seasons/game/models/booster.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
final cal = DailyRewardCalendar();
|
||||
|
||||
DateTime d(int day) => DateTime(2026, 6, day);
|
||||
|
||||
test('first ever claim is day 1', () {
|
||||
final r = cal.resolve(lastClaimedYmd: null, storedDay: 0, today: d(18));
|
||||
expect(r.claimable, isTrue);
|
||||
expect(r.day, 1);
|
||||
});
|
||||
|
||||
test('claiming again the same day is not claimable', () {
|
||||
final r = cal.resolve(
|
||||
lastClaimedYmd: '2026-06-18', storedDay: 1, today: d(18));
|
||||
expect(r.claimable, isFalse);
|
||||
});
|
||||
|
||||
test('a consecutive day advances the calendar', () {
|
||||
final r = cal.resolve(
|
||||
lastClaimedYmd: '2026-06-18', storedDay: 3, today: d(19));
|
||||
expect(r.claimable, isTrue);
|
||||
expect(r.day, 4);
|
||||
});
|
||||
|
||||
test('day 7 wraps back to day 1', () {
|
||||
final r = cal.resolve(
|
||||
lastClaimedYmd: '2026-06-18', storedDay: 7, today: d(19));
|
||||
expect(r.day, 1);
|
||||
});
|
||||
|
||||
test('a missed day resets to day 1', () {
|
||||
final r = cal.resolve(
|
||||
lastClaimedYmd: '2026-06-18', storedDay: 4, today: d(20));
|
||||
expect(r.claimable, isTrue);
|
||||
expect(r.day, 1);
|
||||
});
|
||||
|
||||
test('reward table covers days 1..7 and day 7 is the jackpot', () {
|
||||
expect(cal.rewardFor(1), {BoosterType.hammer: 1});
|
||||
expect(cal.rewardFor(7),
|
||||
{BoosterType.hammer: 2, BoosterType.shuffle: 2, BoosterType.lineBomb: 2});
|
||||
});
|
||||
|
||||
test('ymd formats a date as YYYY-MM-DD', () {
|
||||
expect(cal.ymd(DateTime(2026, 6, 7)), '2026-06-07');
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user