Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8dee5ca
initial setup and add fortune function and empty function stubs
wc2184 Oct 28, 2025
abff97b
Merge pull request #1 from swe-students-fall2025/feature/initialSetup
PranathiChin Oct 28, 2025
55a8c3f
future predictions functions
Oct 28, 2025
533fee5
Merge pull request #2 from swe-students-fall2025/pran-futurePredictions
Deng-Hanjun Oct 28, 2025
7eb1370
testing something with account
PranathiChin Oct 28, 2025
86136a3
testing
PranathiChin Oct 28, 2025
695b4d8
testing
PranathiChin Oct 28, 2025
f587d32
Merge pull request #3 from swe-students-fall2025/pran-futurePredictions
PranathiChin Oct 28, 2025
9eed1b0
reset
PranathiChin Oct 28, 2025
0fde314
Merge pull request #4 from swe-students-fall2025/pran-futurePredictions
PranathiChin Oct 28, 2025
d671704
adding future predictions function
PranathiChin Oct 28, 2025
58d9e5c
Merge pull request #5 from swe-students-fall2025/pran-futurePredictions
wc2184 Oct 28, 2025
9c1dad4
basic compatibility score
zz4206 Oct 29, 2025
5d757fd
Merge remote-tracking branch 'origin' into may
zz4206 Oct 29, 2025
03b6068
compatibility score implemented
zz4206 Oct 29, 2025
a8881dc
Merge pull request #6 from swe-students-fall2025/may
PranathiChin Oct 29, 2025
a2551bd
implemented lucky number
SamRawdon Oct 30, 2025
1d50452
Merge pull request #7 from swe-students-fall2025/luckyNumber
PranathiChin Oct 30, 2025
8fd350a
some compatibility score tests
zz4206 Nov 3, 2025
24e20ef
Merge remote-tracking branch 'origin' into may
zz4206 Nov 3, 2025
be918ad
compatibility score fixed after test
zz4206 Nov 3, 2025
e525384
Merge pull request #8 from swe-students-fall2025/may
SamRawdon Nov 3, 2025
e55fc09
Implement predict_day
Deng-Hanjun Nov 3, 2025
a643a9d
Merge pull request #9 from swe-students-fall2025/Hanjun_dev
SamRawdon Nov 3, 2025
3ea466f
add menu to main
zz4206 Nov 4, 2025
302f380
Merge pull request #10 from swe-students-fall2025/may
PranathiChin Nov 4, 2025
41e508f
fixed luckynumber and main
zz4206 Nov 4, 2025
544441a
Update predictDay, fortune, and main
Deng-Hanjun Nov 4, 2025
5bda06e
Merge pull request #11 from swe-students-fall2025/may
Deng-Hanjun Nov 4, 2025
9576676
Merge remote-tracking branch 'origin/main' into Hanjun_dev and solve …
Deng-Hanjun Nov 4, 2025
77fff2c
added lucky number testst
SamRawdon Nov 4, 2025
ff8eec4
Merge pull request #12 from swe-students-fall2025/Hanjun_dev
SamRawdon Nov 4, 2025
bc8c627
Merge pull request #13 from swe-students-fall2025/lucky_number_tests
zz4206 Nov 4, 2025
7eec4fc
fix tests
zz4206 Nov 4, 2025
1e7df46
Merge pull request #14 from swe-students-fall2025/may
Deng-Hanjun Nov 4, 2025
2dead50
update predict_day and add test_predict_day
Deng-Hanjun Nov 4, 2025
6e64e23
Merge pull request #15 from swe-students-fall2025/Hanjun_dev
zz4206 Nov 5, 2025
cc7b401
fix predictDay and predictDay tests
zz4206 Nov 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
pytest = "*"
coverage = "*"
pytest-cov = "*"

[dev-packages]

[requires]
python_version = "3.10"
237 changes: 237 additions & 0 deletions Pipfile.lock

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[project]
name = "fortuneluckpredictor"
version = "0.0.1"
authors = [
{ name="Example Author", email="author@example.com" },
]
description = "Fortune & luck predictor. Returns lucky numbers, fortunes, and horoscope-like results."
readme = "README.md"
requires-python = ">=3.9"
classifiers = [
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
]
license = "MIT"
license-files = ["LICEN[CS]E*"]

[project.urls]
Homepage = "https://github.com/swe-students-fall2025/3-python-package-team_boreal"
Issues = "https://github.com/swe-students-fall2025/3-python-package-team_boreal/issues"
Empty file.
56 changes: 56 additions & 0 deletions src/fortuneluckpredictor/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from .fortune import get_fortune
from .futurePredictions import futurePrediction
from .compatibility_score import compatibility_score
from .luckyNumber import get_lucky_number
from .predictDay import predict_day

def main() -> None:

print("\n✨🔮✨==============================✨🔮✨")
print(" Welcome to Fortune Luck Predictor! ")
print("✨🔮✨==============================✨🔮✨")
print(" (づ。◕‿‿◕。)づ ✨ 🧙‍♂️ 🍀 🦄 ")

while True:
print("1. Get your fortune ✨")
print("2. Predict your future 🔮")
print("3. Predict your day ☀️")
print("4. Compatibility score 💞")
print("5. Get your lucky number 🍀")
print("6. Exit 🚪")
choice = input("Choose an option (1-6): ").strip()

if choice == "1":
print("\nYour fortune:")
print(get_fortune())
elif choice == "2":
name = input("Enter your name: ").strip()
print("\n" + futurePrediction(name))
elif choice == "3":
day = input("Enter a day of the week: ").strip()
try:
print("\n" + predict_day(day or None))
except Exception as e:
print(f"Error: {e}")
elif choice == "4":
name1 = input("Enter the first name: ").strip()
name2 = input("Enter the second name: ").strip()
print("\n" + compatibility_score(name1, name2))
elif choice == "5":
print("Your lucky number:")
print(get_lucky_number())
elif choice == "6":
print("Goodbye! ✨")
break
else:
print("Invalid choice. Please enter a number from 1 to 6.")

continue_prompt = input("\nWould you like to try another option? (yes/no): ").strip().lower()
if continue_prompt not in ('yes', 'y'):
print("Goodbye! ✨")
break

print("\n")

if __name__ == "__main__":
main()
31 changes: 31 additions & 0 deletions src/fortuneluckpredictor/compatibility_score.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
def compatibility_score(name1: str, name2: str) -> str:
score = 0
vowels = "aeiou"
c = [] # each vowel's count
n1 = name1.lower()
n2 = name2.lower()
for v in vowels:
c1 = n1.count(v)
c2 = n2.count(v)
n = abs(c1 - c2)
c.append(n)

# Add vowel counts next to each other together until one digit remains
while(len(c) > 1):
new_c = []
for i in range(len(c) - 1):
new_c.append((c[i] + c[i+1]) % 10)
c = new_c

score = c[0]
# compatibility message based on final score
if score <= 2:
message = "Perfect match — pure harmony! 💞"
elif score <= 4:
message = "You two vibe really well! ❤️"
elif score <= 7:
message = "There's potential — stay open and see where it goes! 🌈"
else:
message = "You'll meet someone wonderful who complements you perfectly! 💫"

return f"Compatibility score: {score}. {message}"
30 changes: 30 additions & 0 deletions src/fortuneluckpredictor/fortune.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import random

fortunes = [
"Your resume will land on the perfect Meta recruiter's desk this week.",
"A Meta engineer will soon endorse your skills and open a new door.",
"The next coding interview you take will feel like designing the future of social connections.",
"Your grind on system design is about to pay off with a Reality Labs breakthrough.",
"A friendly referral will unlock the Meta pipeline you've been eyeing.",
"An unexpected DM from a Meta recruiter will kickstart your big tech journey.",
"Your portfolio will impress a Meta hiring manager far more than you expect.",
"A well-timed leetcode streak will boost your confidence for the Meta onsite.",
"Soon you'll celebrate a Meta offer with your closest supporters.",
"The next recruiter call you accept will change the trajectory of your career in the metaverse.",
"A spontaneous trip will lead to a story you retell for years.",
"Your curiosity will uncover a hobby that becomes a passion.",
"A long-standing question will be answered in the most unexpected way.",
"You will reconnect with someone who inspires you to dream bigger.",
"Small daily habits will compound into a breakthrough moment.",
"A random compliment will brighten your day and boost your confidence.",
"Your next challenge will reveal strength you didn't know you had.",
"A creative idea will blossom into a project that excites others.",
"Soon you will realize you are exactly where you need to be.",
"An opportunity to help someone will come, and your kindness will be remembered.",
]

def get_fortune(cookie: bool = True) -> str:
if cookie:
return f"🍪 {random.choice(fortunes)}"
else:
return random.choice(fortunes)
31 changes: 31 additions & 0 deletions src/fortuneluckpredictor/futurePredictions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import random

def futurePrediction(name1: str) -> str:
careers = [
"software engineer", "doctor",
"lawyer", "teacher", "artist",
"entrepreneur", "scientist",
"musician", "architect", "chef",
"engineer", "journalist",
"psychologist", "designer", "consultant",
"nurse", "researcher", "manager",
"analyst", "inventor"
]

marriage_ages = list(range(25, 40))
kids_counts = list(range(0, 4))
success_levels = ["very successful", "successful",
"somewhat successful", "moderately successful"]

name = sum(ord(c) for c in name1)

random.seed(name)
career = random.choice(careers)
marriage_age = random.choice(marriage_ages)
kids_count = random.choice(kids_counts)
success = random.choice(success_levels)

kids_str = "kids" if kids_count != 1 else "kid"
kids_phrase = f"with {kids_count} {kids_str}" if kids_count > 0 else "with no kids"

return f"{name1} will be a {career} and get married at {marriage_age} {kids_phrase} and you will be {success}"
43 changes: 43 additions & 0 deletions src/fortuneluckpredictor/luckyNumber.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import random
import math
from datetime import datetime

try:
from zoneinfo import ZoneInfo
_tz = ZoneInfo("America/New_York")
except Exception:
_tz = None

def get_lucky_number(r=(1, 100)):
a, b = r
if a > b:
a, b = b, a
nums = list(range(a, b + 1))

now = datetime.now(_tz) if _tz else datetime.now()
seed = int(now.strftime("%Y%m%d"))
r = random.Random(seed)

day = now.day
month = now.month
wday = now.isoweekday()
hour = now.hour or 24
minute = now.minute or 60
digits_sum = sum(int(x) for x in now.strftime("%Y%m%d%H%M"))

bases = [day, month, wday, hour, minute, digits_sum % (b - a + 1) or 1]
center = sum(bases) / len(bases)
scale = max(1.0, (b - a) / 8.0)

weights = []
for n in nums:
w = 1.0 + math.exp(-abs(n - center) / scale)
w += 0.25 * sum(1 for base in bases if base and n % base == 0)
last_digit = int(str(n)[-1])
w += 0.2 if last_digit == day % 10 else 0.0
w += 0.2 if last_digit == month % 10 else 0.0
w += 0.1 * (str(day) in str(n))
w += 0.1 * (str(month) in str(n))
weights.append(w)

return r.choices(nums, weights=weights, k=1)[0]
47 changes: 47 additions & 0 deletions src/fortuneluckpredictor/predictDay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from .fortune import fortunes
import random
from datetime import datetime

# Each day has its own "theme" or message style
DAY_MESSAGES = {
"monday": "Fresh energy fills your week — set your intentions high.",
"tuesday": "Progress is building; stay focused and take bold steps.",
"wednesday": "Midweek clarity brings productive breakthroughs.",
"thursday": "You’re almost at the finish line — stay sharp and consistent.",
"friday": "Celebrate your wins, no matter how small!",
"saturday": "Recharge your creative battery — inspiration awaits.",
"sunday": "Plan lightly and dream big for the week ahead.",
}

# Support abbreviations (Mon, Tue, etc.)
DAY_ALIASES = {
"mon": "monday",
"tue": "tuesday", "tues": "tuesday",
"wed": "wednesday",
"thu": "thursday", "thur": "thursday", "thurs": "thursday",
"fri": "friday",
"sat": "saturday",
"sun": "sunday",
}

def predict_day(day: str | None = None) -> str:
# If no day provided, use today's day name
if not day or not day.strip():
day = datetime.now().strftime("%A")
d = day.strip().lower()

# Normalize to full day name
key = d if d in DAY_MESSAGES else DAY_ALIASES.get(d)
if not key:
raise ValueError(f"Unrecognized day name: '{day}'")

message = DAY_MESSAGES[key]

# Create a deterministic fortune based on today's date and day name
today = datetime.now().strftime("%Y-%m-%d")
seed_value = hash(today + key) % (2**32)
rng = random.Random(seed_value)
fortune_text = rng.choice(fortunes)

# Format nicely
return f"{key.capitalize()}: {message} Fortune: {fortune_text}"
Empty file added tests/__init__.py
Empty file.
46 changes: 46 additions & 0 deletions tests/test_compatibility_score.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import pytest
from src.fortuneluckpredictor import compatibility_score

# Sample names for testing
@pytest.fixture
def sample_names():
return [
("", "", "Compatibility score: 0. Perfect match — pure harmony! 💞"),
("hello", "hi", "Compatibility score: 4. You two vibe really well! ❤️"),
("moon", "train", "Compatibility score: 5. There's potential — stay open and see where it goes! 🌈"),
("bee", "pool", "Compatibility score: 6. There's potential — stay open and see where it goes! 🌈"),
("aaa", "eee", "Compatibility score: 5. There's potential — stay open and see where it goes! 🌈"),
("hello", "hello", "Compatibility score: 0. Perfect match — pure harmony! 💞"),
("Michael", "Michelle", "Compatibility score: 5. There's potential — stay open and see where it goes! 🌈"),
("James", "Emma", "Compatibility score: 0. Perfect match — pure harmony! 💞"),
("Isabella", "Alexander", "Compatibility score: 0. Perfect match — pure harmony! 💞"),
("William", "Olivia", "Compatibility score: 4. You two vibe really well! ❤️"),
("Sophia", "Daniel", "Compatibility score: 8. You'll meet someone wonderful who complements you perfectly! 💫"),
("Emily", "David", "Compatibility score: 5. There's potential — stay open and see where it goes! 🌈"),
("Ethan", "Ava", "Compatibility score: 5. There's potential — stay open and see where it goes! 🌈"),
("Benjamin", "Charlotte", "Compatibility score: 0. Perfect match — pure harmony! 💞"),
("Mia", "Lucas", "Compatibility score: 7. There's potential — stay open and see where it goes! 🌈")
]

# Test sanity check
def test_sanity_check():
assert True

# Test that output is a string
def test_format(sample_names):
for n1, n2, _ in sample_names:
output = compatibility_score.compatibility_score(n1, n2)
assert isinstance(output, str)

# Test exact outputs for sample names
def test_exact_match(sample_names):
for n1, n2, expected in sample_names:
actual = compatibility_score.compatibility_score(n1, n2)
assert actual == expected, f"for ({n1},{n2}) expected {expected!r} but got {actual!r}"

# Test that the compatibility score is same for same inputs
def test_consistent_output(sample_names):
for n1, n2, _ in sample_names:
a = compatibility_score.compatibility_score(n1, n2)
b = compatibility_score.compatibility_score(n1, n2)
assert a == b
66 changes: 66 additions & 0 deletions tests/test_lucky_number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import pytest
import math
from src.fortuneluckpredictor import luckyNumber

@pytest.fixture
def sample_ranges():
return [
(1, 100),
(50, 60),
(100, 1), # reversed range
(7, 7), # single-number range
]

def test_sanity_check():
assert True

# Range check
def test_output_type_and_bounds(sample_ranges):
"""Check that output is an integer within the expected bounds."""
for r in sample_ranges:
result = luckyNumber.get_lucky_number(r)
assert isinstance(result, int)
a, b = r
lo, hi = (a, b) if a <= b else (b, a)
assert lo <= result <= hi, f"{result} not in {lo}-{hi}"

# Returns same number when given same time
def test_consistent_same_seed(monkeypatch):
"""When called within the same minute, output should be stable."""
from datetime import datetime
class FixedTime(datetime):
@classmethod
def now(cls, tz=None):
return datetime(2025, 11, 3, 14, 45)
monkeypatch.setattr(luckyNumber, "datetime", FixedTime)
first = luckyNumber.get_lucky_number((1, 100))
second = luckyNumber.get_lucky_number((1, 100))
assert first == second

# Returns different numbers at different times
def test_distribution_varies_over_time(monkeypatch):
"""Different times should usually yield different lucky numbers."""
from datetime import datetime
class TimeVariant(datetime):
@classmethod
def now(cls, tz=None):
# alternate between two moments
if hasattr(cls, "_toggle"):
del cls._toggle
return datetime(2025, 11, 3, 14, 46)
else:
cls._toggle = True
return datetime(2025, 11, 2, 14, 45)
monkeypatch.setattr(luckyNumber, "datetime", TimeVariant)
n1 = luckyNumber.get_lucky_number((1, 100))
n2 = luckyNumber.get_lucky_number((1, 100))
assert n1 != n2, f"Expected different results across distinct datetimes ({n1} == {n2})"

def test_single_value_range():
"""If range has only one number, that number must be returned."""
assert luckyNumber.get_lucky_number((42, 42)) == 42

def test_reversed_range_handled():
"""Swapped a,b should still produce valid result."""
val = luckyNumber.get_lucky_number((100, 1))
assert 1 <= val <= 100
Loading
Loading