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

Fix/thk playlists #1099

Merged
merged 7 commits into from
Jun 12, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def test_validate_invalid_integer_groups(self):

self.assertEqual(
toontje_hoger_4_absolute.validate_playlist(playlist),
["Groups in playlist sections should be numbers. This playlist has groups: ['a', '2', '4', '4', '11', '7']"]
["Groups in playlist sections should be numbers. This playlist has groups: ['11', '2', '4', '7', 'a']"]
)

def test_validate_invalid_sequential_groups(self):
Expand All @@ -82,7 +82,7 @@ def test_validate_invalid_sequential_groups(self):

self.assertEqual(
toontje_hoger_4_absolute.validate_playlist(playlist),
['Groups in playlist sections should be sequential numbers starting from 1 to the number of sections in the playlist (6). E.g. "1, 2, 3, ... 6"']
['Groups in playlist sections should be sequential numbers starting from 1 to the number of items in the playlist (13). E.g. "1, 2, 3, ... 13"']
)

def test_validate_invalid_tags(self):
Expand Down
2 changes: 1 addition & 1 deletion backend/experiment/rules/toontjehoger_1_mozart.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ def validate_playlist(self, playlist: Playlist):
errors.append("The sections should have different groups")

# Check if sections have group 1 and 2
if not (1 in groups and 2 in groups):
if sorted(groups) != ['1', '2']:
errors.append("The sections should have groups 1 and 2")

return errors
4 changes: 2 additions & 2 deletions backend/experiment/rules/toontjehoger_2_preverbal.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def validate_playlist(self, playlist: Playlist):
if first_round_sections.count() != 3:
errors.append(
'There should be 3 sections with group 1 (first round)')
if sorted(first_round_sections.values('tag').distinct()) != ['a', 'b', 'c']:
if sorted(first_round_sections.values_list('tag', flat=True).distinct()) != ['a', 'b', 'c']:
errors.append(
'The first round sections should have tags a, b, c'
)
Expand All @@ -49,7 +49,7 @@ def validate_playlist(self, playlist: Playlist):
if second_round_sections.count() != 2:
errors.append(
'There should be 2 sections with group 2 (second round)')
if sorted(second_round_sections.values('tag').distinct()) != ['a', 'b']:
if sorted(second_round_sections.values_list('tag', flat=True).distinct()) != ['a', 'b']:
errors.append(
'The second round sections should have tags a, b'
)
Expand Down
5 changes: 3 additions & 2 deletions backend/experiment/rules/toontjehoger_3_plink.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ def validate_playlist(self, playlist: Playlist):
if len(artist_titles) != len(sections):
errors.append(
'Sections should have unique combinations of song.artist and song.name fields.')
self.validate_era_and_mood(sections, errors)
errors += self.validate_era_and_mood(sections)
return errors

def validate_era_and_mood(self, sections, errors):
def validate_era_and_mood(self, sections):
errors = []
eras = sorted(sections.order_by('tag').values_list(
'tag', flat=True).distinct())
if not all(re.match(r'[0-9]0s', e) for e in eras):
Expand Down
5 changes: 3 additions & 2 deletions backend/experiment/rules/toontjehoger_4_absolute.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,16 @@ def validate_playlist_groups(self, groups):
# Check if the groups are sequential and unique
integer_groups.sort()
if integer_groups != list(range(1, len(groups) + 1)):
return ['Groups in playlist sections should be sequential numbers starting from 1 to the number of sections in the playlist ({}). E.g. "1, 2, 3, ... {}"'.format(len(groups), len(groups))]
return ['Groups in playlist sections should be sequential numbers starting from 1 to the number of items in the playlist ({}). E.g. "1, 2, 3, ... {}"'.format(self.PLAYLIST_ITEMS, self.PLAYLIST_ITEMS)]
Copy link
Contributor

Choose a reason for hiding this comment

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

While the original Toontjehoger Absolute game has 13 playlist items, this validator should be flexible: it should be entirely possible to implement ToontjeHoger Absolute with less playlist items, without having to override the validator.

I thought this validator should be flexible, or have I misunderstood what you wrote? 😄

Copy link
Collaborator Author

@BeritJanssen BeritJanssen Jun 12, 2024

Choose a reason for hiding this comment

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

This was a misunderstanding indeed: with "playlist items" I meant, "items, of which there are three variants". So n_sections != self.PLAYLIST_ITEMS. Hurrying through code reviews is not a good idea, I should've caught this before.


return []

def validate_playlist(self, playlist: Playlist):
errors = super().validate_playlist(playlist)

# Get group values from sections, ordered by group
groups = list(playlist.section_set.values_list('group', flat=True))
groups = list(playlist.section_set.values_list(
'group', flat=True).distinct())
Copy link
Collaborator Author

@BeritJanssen BeritJanssen Jun 12, 2024

Choose a reason for hiding this comment

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

This is the actual needed change though - before, there were as many groups as there were sections. I still think the reference to PLAYLIST_ITEMS in the validate_playlist_groups function is more readable.


# Check if the groups are sequential and unique
errors += self.validate_playlist_groups(groups)
Expand Down
3 changes: 3 additions & 0 deletions backend/experiment/rules/toontjehogerkids_3_plink.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class ToontjeHogerKids3Plink(ToontjeHoger3Plink):
SCORE_EXTRA_2_CORRECT = 4
SCORE_EXTRA_WRONG = 0

def validate_era_and_mood(self, sections):
return []

def first_round(self, experiment):
"""Create data for the first experiment rounds."""

Expand Down
2 changes: 1 addition & 1 deletion backend/experiment/rules/toontjehogerkids_4_absolute.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

class ToontjeHogerKids4Absolute(ToontjeHoger4Absolute):
ID = 'TOONTJE_HOGER_KIDS_4_ABSOLUTE'
PLAYLIST_ITEMS = 13
PLAYLIST_ITEMS = 12

def first_round(self, experiment):
"""Create data for the first experiment rounds."""
Expand Down
85 changes: 14 additions & 71 deletions backend/experiment/rules/toontjehogerkids_5_tempo.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,84 +37,37 @@ def first_round(self, experiment):
def get_random_section_pair(self, session, genre):
"""
- session: current Session
- genre: (C)lassic (J)azz (R)ock

Voor de track: genereer drie random integers van 1-5 (bijv. [4 2 4])
Plak deze aan de letters C, J en R (bijv. [C4, J2, R4])
Voor het paar: genereer drie random integers van 1-2 (bijv. [1 2 2])
Plak deze aan de letter P (bijv. P1, P2, P2)
We willen zowel de originele als de veranderde versie van het paar. Dus combineer
bovenstaande met OR en CH (bijv. “C4_P1_OR”, “C4_P1_CH”, etc.)
- genre: unused

return a section from an unused song, in both its original and changed variant
"""
# Previous tags
previous_tags = [
result.section.tag for result in session.result_set.all()]

# Get a random, unused track
# Loop until there is a valid tag
iterations = 0
valid_tag = False
tag_base = ""
tag_original = ""
while (not valid_tag):
track = random.choice([1, 2, 3, 4, 5])
pair = random.choice([1, 2])
tag_base = "{}{}_P{}_".format(genre.upper(), track, pair, )
tag_original = tag_base + "OR"
if not (tag_original in previous_tags):
valid_tag = True

# Failsafe: prevent infinite loop
# If this happens, just reuse a track
iterations += 1
if iterations > 10:
valid_tag = True

tag_changed = tag_base + "CH"

section_original = session.section_from_any_song(
filter_by={'tag': tag_original, 'group': "or"})

section_original = session.section_from_unused_song(
filter_by={'group': "or"})

if not section_original:
raise Exception(
"Error: could not find original section: {}".format(tag_original))

section_changed = self.get_section_changed(
session=session, tag=tag_changed)
session=session, song=section_original.song)

sections = [section_original, section_changed]
random.shuffle(sections)
return sections

def get_section_changed(self, session, tag):
section_changed = session.section_from_any_song(
filter_by={'tag': tag, 'group': "ch"})
def get_section_changed(self, session, song):
section_changed = session.playlist.section_set.get(
song__name=song.name, song__artist=song.artist, group='ch'
)
if not section_changed:
raise Exception(
"Error: could not find changed section: {}".format(tag))
"Error: could not find changed section: {}".format(song))
return section_changed

def get_trial_question(self):
return "Kan jij horen waar de klikjes goed bij de maat van de muziek passen?"

def get_section_pair_from_result(self, result):
section_original = result.section

if section_original is None:
raise Exception(
"Error: could not get section from result")

tag_changed = section_original.tag.replace("OR", "CH")
section_changed = self.get_section_changed(
session=result.session, tag=tag_changed)

if section_changed is None:
raise Exception(
"Error: could not get changed section for tag: {}".format(
tag_changed))

return (section_original, section_changed)

def get_score(self, session):
# Feedback
last_result = session.last_result()
Expand All @@ -130,20 +83,10 @@ def get_score(self, session):
feedback = "Helaas! Het juiste antwoord was {}.".format(
last_result.expected_response.upper())

section_original, section_changed = self.get_section_pair_from_result(
last_result)

# Create feedback message
# - Track names are always the same
# - Artist could be different
if section_original.song.artist == section_changed.song.artist:
feedback += " Je hoorde {}, in beide fragmenten uitgevoerd door {}.".format(
last_result.section.song.name, last_result.section.song.artist)
else:
section_a = section_original if last_result.expected_response == "A" else section_changed
section_b = section_changed if section_a.id == section_original.id else section_original
feedback += " Je hoorde {} uitgevoerd door A) {} en B) {}.".format(
section_a.song.name, non_breaking_spaces(section_a.song.artist), non_breaking_spaces(section_b.song.artist))
feedback += " Je hoorde '{}' van {}.".format(
last_result.section.song.name, last_result.section.song.artist)

# Return score view
config = {'show_total_score': True}
Expand Down
Loading