Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adagrams: Snow Leopards ( Kae & Diana) #66

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# AdaGrams

## Collaboration Plan:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice documentation of your collaboration plan.


- EST Time Zone/ Best time to meet are Ada Breaks & Evenings
- WRAP UP at 9PM. Hard Stop at 10 PM.
- Preferred Method of Contact: Slack or Email(defer to Slack for contact details)
- Keep each other informed on time block status
- Body-Doubling w/ or w/o Music
- DUE FRIDAY 11:30 EST
- Meeting times shared via Google Calendar
-

## Skills Assessed

- Following directions and reading comprehension
Expand Down Expand Up @@ -95,16 +106,16 @@ $ pip install -r requirements.txt
Summary of one-time project setup:

One person:
- [ ] Fork the project respository
- [ ] Invite team members to the respository
- [X] Fork the project respository
- [X] Invite team members to the respository

All team members:
- [ ] `cd` into your `projects` folder
- [ ] Clone the project onto your machine
- [ ] `cd` into the `adagrams-py` folder
- [ ] Create the virtual environment `venv`
- [ ] Activate the virtual environment `venv`
- [ ] Install the dependencies with `pip`
- [X] `cd` into your `projects` folder
- [X] Clone the project onto your machine
- [X] `cd` into the `adagrams-py` folder
- [X] Create the virtual environment `venv`
- [X] Activate the virtual environment `venv`
- [X] Install the dependencies with `pip`

## Project Development Workflow

Expand Down Expand Up @@ -289,5 +300,5 @@ Implement a function called `get_highest_word_score` in `game.py`. This method s
- If the there are multiple words that are the same score and the same length, pick the first one in the supplied list



- Here is a test line.

133 changes: 125 additions & 8 deletions adagrams/game.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,128 @@
def draw_letters():
pass
def mystery(numbers):
index = 0
while index < len(numbers):
numbers[index] *= 2
index += 1

return numbers

def uses_available_letters(word, letter_bank):
pass
nums = [1, 2, 3, 4, 5]
mystery(nums)

def score_word(word):
pass
print(nums[3])

def get_highest_word_score(word_list):
pass





# def get_fire_students(students):
# '''
# INPUT: A list of dictionaries with the "name" and "class" key-value pairs.
# Example: get_fire_students([{ "name": "Ada", "class": "fire"}, { "name": "Taylor", "class": "earth" }])
# RETURN VALUE: A list of dictionaries with **only** the students in the "fire" class.
# '''
# temp = []
# students = students.copy()
#
# while students:
# student = students.pop()
# if student["class"] == "fire":
# temp.append(student)
# #
# # while temp:
# # students.append(temp.pop())
# print(students)
# return students
#
#
# get_fire_students([{ "name": "Ada", "class": "fire"}, { "name": "Taylor", "class": "earth" }])

cur_score = score_word(word)
word_len = -len(word)
has_10 = word_len == -10 # True if word length is 10.

# def hamming_distance(strand1, strand2):
# count_of_differences = 0
# index = 0
#
#
# if len(strand1) == 0 or len(strand2) == 0:
# raise ValueError("One of your inputs is invalid, please try again.")
#
#
# for letter in strand2:
# # if letter[index] not in strand2[index]:
# count_of_differences += 1
# index += 1
#
#
# return count_of_differences
#
# print(hamming_distance("GAGCCTACTAACGGGAT", "CATCGTAATGACGGCCT"))
# print(hamming_distance("GAG", "GAG"))
# print(hamming_distance("GAG", ""))


# def score(word):
#
# point_system = {
# ("A", "E", "I", "O", "U", "L", "N", "R", "S", "T"): 1,
# ("D", "G"): 2,
# ("B", "C", "M", "P"): 3,
# ("F", "H", "V", "W", "Y"): 4,
# "K": 5,
# ("J", "X"): 8,
# ("Q", "Z"): 10
# }
#
# total_score = 0
#
# try:
# word = word.upper()
# except AttributeError as err:
# return "You've entered a number, please enter a letter and try again."
# except Exception:
# print("You've entered a number, please enter a letter and try again.")
# raise
#
# letters_of_word = list(word)
#
# if len(letters_of_word) == 0:
# return None
#
# else:
# for letter in letters_of_word:
# for key,value in point_system.items():
# if letter in key:
# total_score += value
# return total_score
#
#
# # print(score("Dog"))
# # print(score(123))
# print(score("supercalifragilisticexpialidocious"))
# print(score(''))


# example input 1: "supercalifragilisticexpialidocious"
# expected output 1: 56

# example input 2: "Français"
# expected output 2:
#
# def test_ridiculous_words():
# # arrange
# word = "supercalifragilisticexpialidocious"
# # act
# result = score(word)
# # assert
# assert result = 56
#
# def test_letter_not_in_English():
# # arrange
# word = "Français"
# # act
# result = score(word)
# # assert
# result =
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
attrs==20.3.0
iniconfig==1.1.1
numpy==1.23.3
packaging==20.8
pluggy==0.13.1
py==1.10.0
pyparsing==2.4.7
pytest==7.1.1
scipy==1.9.1
toml==0.10.2
tomli==2.0.1
64 changes: 64 additions & 0 deletions tests/test_wave_01.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import pytest
from scipy import stats as stats
from pprint import pprint
from collections import Counter

from adagrams.game import draw_letters

Expand Down Expand Up @@ -65,3 +68,64 @@ def test_letter_not_selected_too_many_times():
# Assert
for letter in letters:
assert letter_freq[letter] <= LETTER_POOL[letter]

def test_chi_square_frequencies():

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I DO NOT have stats experience, so beyond being aware of the chi-square test sounding like the right thing to do, I can only say that your approach makes sense to me: tally up the observed letter counts over a "large" number of runs, and check whether the distribution looks like the expected distribution from the tile counts.

The test that we supplied really just checks that no impossible hands can be drawn, and while it would be possible for that test to be "defeated" by a faulty implementation (i.e., the implementation might not be properly enforceing the limits, but for all of the 1000 test runs, it never happens to exceed any), it will never yield a false negative. It will never fail as long as the implementation is correct.

Statistical based tests are a touchy subject. We want to be sure that unit tests NEVER have a chance of failing for working code. EVen worse if it fails sporadically. So any statistical test would need to be careful tuned to ensure that the tolerances are such that they would NEVER cause the test to fail. If there is a test that sporadically fails, that trains the programmers to ignore the test. If it fails, "it's just that test that fails sometimes," and that can mean that if it truly is failing, no one will take any notice.

Code that depends on randomness does present a problem for testing. Another approach is to avoid the randomness entirely in the test. In our code, rather than directly relying on a library function that has randomness baked in (like randint or sample) we might have our code depend on a passed in supplier of randomness. In the real code, we can provide an implementation that uses the typical provider of randomness, but in the test, we might pass in a more deterministic provider that we know will always produce a particular result, turning the test from a check of statistical probability more towards a test of expected stable behavior.

If we do still want to run some statistical tests (probably still a good idea), we might store them in a different suite of tests. There are more kinds of tests than just unit tests (short, small tests that we run frequently while developing to check basic behaviors), like integration testing, smoke testing, or fuzz testing. These aren't usually run by devs all the time, and hence, might provide a better situation for the test runner to spend more time looking into any failures without it becoming a blocker to the regular devlopment cycle. As it is, this test actually did fail for me once in the few times I ran it! 😱


# this *should* work
# technique adapted from
# http://practicalcryptography.com/cryptanalysis/text-characterisation/chi-squared-statistic/
# TODO: get someone with better stats experience to
# double-check this

# arrange/act


# normalize LETTER_POOL frequencies
pool_sum = sum(LETTER_POOL.values())
pool_freqs = {letter : (value / pool_sum) for letter,value in LETTER_POOL.items()}

# collect our sample
sample_counter = Counter()
for i in range (500):
letters = draw_letters()
for letter in letters:
sample_counter[letter] += 1

# -------------
# Test the test
# -------------
#
# Uncomment for big fail!

# Add a bunch of extra "Q" tiles!
# sample_counter['Q'] *= 2

# Take away some "E" tiles!
# sample_counter['E'] /= 2

# organize our expected and sample
# into parallel lists
expected = []
sample = []
total = sample_counter.total()
for letter, freq in pool_freqs.items():
expected.append(freq * total)
sample.append(sample_counter[letter])

# pprint(sample)
# pprint(expected)
# pprint(sum(expected))
chi = stats.chisquare(sample, expected)
pprint(chi.pvalue)

# low is bad, high is good
assert chi.pvalue > 0.05









4 changes: 4 additions & 0 deletions tests/test_wave_02.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ def test_uses_available_letters_true_word_in_letter_bank():
# Assert
assert is_valid == True

# Passes

def test_uses_available_letters_false_word_in_letter_bank():
# Arrange
letters = ["D", "O", "X", "X", "X", "X", "X", "X", "X", "X"]
Expand All @@ -24,6 +26,8 @@ def test_uses_available_letters_false_word_in_letter_bank():
# Assert
assert is_valid == False

# Passes

def test_uses_available_letters_false_word_overuses_letter():
# Arrange
letters = ["A", "X", "X", "X", "X", "X", "X", "X", "X", "X"]
Expand Down