示例#1
0
def get_path(filename):
	"""
	get_path
		takes in a filename, loads the data, and returns the
		path found by Harmony, or None

	Parameters
		data: dictionary mapping n, colors, and swaps for 
			a given initial state of the game
	"""
	data = get_harmony_text(filename)

	# get values from data dict
	n = data["n"]
	colors = data["colors"]
	swaps = data["swaps"]
	test = data["test"]
	# this formatting is if filename = "cases/#.in"
	print "Test {}: {}\n".format(filename[6], test)

	# load and solve game
	harmony = Harmony(n, colors, swaps)
	path = harmony.solve()

	return path
示例#2
0
    def testLogic_game_solved(self):
        """
		testLogic_game_solved
			tests whether a solved game is reported as solved
		"""
        n = 2
        colors = [0, 0, 1, 1]
        swaps = [0, 0, 0, 0]
        harmony = Harmony(n, colors, swaps)

        self.assertTrue(harmony.game_solved())
示例#3
0
    def testSearch_none(self):
        """
		testSearch_none
			tests if None is returned upon an impossible situation
		"""
        n = 2
        colors = [1, 1, 0, 0]
        swaps = [0, 0, 0, 0]
        harmony = Harmony(n, colors, swaps)
        path = harmony.solve()

        assert path is None
示例#4
0
    def testPathfinding_get_swappable_none(self):
        """
		testPathfinding_get_swappable_none
			tests that get_swappable returns an empty list
			given no swaps available
		"""
        n = 2
        colors = [0, 0, 1, 1]
        swaps = [0, 0, 0, 0]
        harmony = Harmony(n, colors, swaps)

        self.assertEqual(harmony.get_swappable(), [])
示例#5
0
    def testLogic_has_waps_left_none(self):
        """
		testLogic_has_waps_left_none
			tests whether swaps_left, given no remaining total
			swaps, returns False
		"""
        n = 2
        colors = [0, 0, 1, 1]
        swaps = [0, 0, 0, 0]
        harmony = Harmony(n, colors, swaps)

        self.assertFalse(harmony.has_swaps_left())
示例#6
0
    def __init__(self, *args, **kwargs):
        """
		constructor
			initializes and stores a 2 by 2 game of
			Harmony for use in tests
		"""
        super(TestHarmonySmall, self).__init__(*args, **kwargs)

        self.n = 2
        colors = [0, 1, 1, 0]
        swaps = [0, 1, 0, 1]
        self.harmony = Harmony(self.n, colors, swaps)
示例#7
0
    def testSearch_complete(self):
        """
		testSearch_complete
			tests if an empty array is returned upon an already
			solved game
		"""
        n = 2
        colors = [0, 0, 1, 1]
        swaps = [0, 0, 0, 0]
        harmony = Harmony(n, colors, swaps)
        path = harmony.solve()

        self.assertEqual(path, [])
示例#8
0
    def testConstructor_swapping_points_none(self):
        """
		testConstructor_swapping_points_none
			tests that Harmony extracts the correct
			starting points, given that there are none
		"""
        n = 2
        colors = [0, 1, 1, 0]
        swaps = [0, 0, 0, 0]
        harmony = Harmony(n, colors, swaps)

        swapping_points = set()

        self.assertEqual(swapping_points, set(harmony.swapping_points))
示例#9
0
    def testPathfinding_valid_moves_many(self):
        """
		testPathfinding_valid_moves_many
			verifies that the valid_moves locates all valid
			moves, many in this case
		"""
        n = 2
        colors = [1, 1, 0, 0]
        swaps = [1, 1, 1, 1]
        harmony = Harmony(n, colors, swaps)

        index = 0
        valid = [2]

        self.assertEqual(valid, harmony.valid_moves(index))
示例#10
0
    def parse_measure(self, measure, divisions):
        """
        Parses a measure according to the pitch duration token parsing process.
        :param measure: a measure dict in the format created by src/processing/conversion/xml_to_json.py
        :param divisions: the number of divisions a quarter note is split into in this song's MusicXML representation
        :return: a dict containing a list of groups containing the pitch numbers, durations, and bar positions for each
                harmony in a measure
        """
        parsed_measure = {"groups": []}

        tick_idx = 0
        for group in measure["groups"]:
            parsed_group = {
                "harmony": {},
                "pitch_numbers": [],
                "duration_tags": [],
                "bar_positions": []
            }
            harmony = Harmony(group["harmony"])
            parsed_group["harmony"]["root"] = harmony.get_one_hot_root()
            parsed_group["harmony"][
                "pitch_classes"] = harmony.get_seventh_pitch_classes_binary()
            dur_ticks_list = []
            for note_dict in group["notes"]:
                # want monophonic, so we'll just take the top note
                if "chord" in note_dict.keys() or "grace" in note_dict.keys():
                    continue
                else:
                    pitch_num, dur_tag, dur_ticks = self.parse_note(
                        note_dict, divisions)
                    parsed_group["pitch_numbers"].append(pitch_num)
                    parsed_group["duration_tags"].append(dur_tag)
                    dur_ticks_list.append(dur_ticks)
            unnorm_barpos = [
                tick_idx + sum(dur_ticks_list[:i])
                for i in range(len(dur_ticks_list))
            ]
            bar_positions = [
                int((dur_ticks / (4 * divisions)) * 96)
                for dur_ticks in unnorm_barpos
            ]
            parsed_group["bar_positions"] = bar_positions
            parsed_measure["groups"].append(parsed_group)
            tick_idx += sum(dur_ticks_list)
        return parsed_measure
示例#11
0
    def parse_measure(self, measure, scale_factor, prev_harmony):
        """
        For a measure, returns a set of ticks grouped by associated harmony in.
        :param measure: a measure dict in the format created by src/processing/conversion/xml_to_json.py
        :param scale_factor: the scale factor between XML divisions and midi ticks
        :param prev_harmony: a reference to the last harmony used in case a measure has none
        :return: a dict containing a list of groups that contains a harmony and the midi ticks associated with that harmony
        """
        parsed_measure = {"groups": []}
        total_ticks = 0
        for group in measure["groups"]:
            # Set note value for each tick in the measure
            group_ticks = []
            for note in group["notes"]:
                if not "duration" in note:
                    print("Skipping grace note...")
                    continue
                divisions = int(note["duration"]["text"])
                num_ticks = int(scale_factor * divisions)
                index = self.get_note_index(note)

                for i in range(num_ticks):
                    tick = [0 for _ in range(MIDI_RANGE)]
                    tick[index] = 1
                    group_ticks.append(tick)

            total_ticks += len(group_ticks)

            if not group["harmony"]:
                parsed_measure["groups"].append({
                    "harmony": prev_harmony,
                    "ticks": group_ticks
                })
            else:
                harmony = Harmony(group["harmony"])
                harmony_dict = {
                    "root": harmony.get_one_hot_root(),
                    "pitch_classes":
                    harmony.get_seventh_pitch_classes_binary()
                }
                prev_harmony = harmony_dict
                parsed_measure["groups"].append({
                    "harmony": harmony_dict,
                    "ticks": group_ticks
                })

            # Mitigate ticks for chords that occur mid-note
            for i, group in enumerate(parsed_measure["groups"]):
                try:
                    if not group["ticks"]:
                        # Handle the case of no harmony at the start of the bar
                        if not 0 in measure["harmonies_start"]:
                            measure["harmonies_start"].insert(0, 0)

                        correct_len_of_prev_harmony = int(
                            scale_factor * (measure["harmonies_start"][i] -
                                            measure["harmonies_start"][i - 1]))

                        group["ticks"].extend(parsed_measure["groups"][
                            i - 1]["ticks"][correct_len_of_prev_harmony:])
                        parsed_measure["groups"][
                            i - 1]["ticks"] = parsed_measure["groups"][
                                i - 1]["ticks"][:correct_len_of_prev_harmony]
                except:
                    import pdb
                    pdb.set_trace()
                    raise (
                        "No ticks in the first group of a measure! (in fix for chords mid-note)"
                    )

        if total_ticks > TICKS_PER_BEAT * 4:
            raise Exception("OH NO BRO. YOUR TICKS ARE TOO MUCH YO")

        i = 0
        while total_ticks < TICKS_PER_BEAT * 4:
            group = parsed_measure["groups"][i]
            spacer_tick = [0 for _ in range(MIDI_RANGE)]
            spacer_tick[0] = 1  # fill with rests
            group["ticks"].append(spacer_tick)
            i = (i + 1) % len(parsed_measure["groups"])
            total_ticks += 1

        parsed_measure["num_ticks"] = total_ticks
        return parsed_measure, prev_harmony