[Magic Brew] Further Ideas

Towards theoretical perfection ...

Current Issues

Main issues:

  1. Incomplete knowledge base structure
    • Manual filter definition (creation + new set release updates)
    • Manual filter clustering (ad hoc)
    • Manual glossary selection (ad hoc)
    • Manual glossary/filter linkage (ad hoc)
    • Implementation limits (HTTrack/Gatherer search query length)
    Root cause = manual work + external system/tool limitations

  2. Incomplete knowledge base data
    • Expressive power limits (Oracle card text pattern matching)
    • Manual regression test precision limits (false positives/negatives inspection)
    Root cause = shallow knowledge representation + external system/tool limitations

  3. Untimely knowledge base generation
    • Manual knowledge base structure (creation + new set release updates)
    • Manual knowledge base data (false positives/negatives inspection)
    • Automated knowledge base generation (excessive web crawling)
    Root cause = manual work + shallow knowledge representation + external system/tool limitations

Ultimate Solution

Cards integration within the knowledge base itself, i.e. bidirectional linkage between search filter definitions and cards, instead of unidirectional linkage from search filter definitions to Gatherer search filter results to cards.

This would require translating each existing Gatherer card (and in particular its Oracle card text) into a more fundamental representation. In analogy to e.g. Java computer programs, or more precisely the equivalent Java Byte Code instructions, being executable on a Java Virtual Machine, the Magic: The Gathering representation layer should consist of MGL (i.e. 'Magic Game Language') card declarations, or more precisely the equivalent MGC (i.e. 'Magic Game Code') instructions, directly executable on a MVM (i.e. 'Magic Virtual Machine') = Comprehensive Rules implementation. Filter definitions would then be expressed in MQL (i.e. 'Magic Query Language'), i.e. advanced 'tagging' (e.g. by means of Scryfall Tagger).

Let it be clear that all of this goes way beyond the current pragmatic Magic Brew approach.

Ultimate solution benefits:

Ultimate solution requirement:

Tech Hint

To intuitively illustrate above mentioned MGL, MGC, MVM, and MQL concepts, please find the simplified triggered ability example 'When Cyclopean Mummy dies, exile it.' in hypothetical pseudo-code below. This pseudo-code by no means provides any indication of any actual solution realization. The [*1*] .. [*7*] markers highlight the main points in the event-driven execution flow (i.e. from creature death to exile).

MQL_FILTER sacrifice_or_die_or_destroy
{
	LEAVE_BATTLEFIELD + ENTER_GRAVEYARD
}

MGL_ABILITY abi =
{
	ability:TRIGGERED_ABILITY . condition:ZONE-CHANGE . object == abi . source
	ability:TRIGGERED_ABILITY . condition:ZONE-CHANGE . event#1 == LEAVE_BATTLEFIELD
	ability:TRIGGERED_ABILITY . condition:ZONE-CHANGE . event#2:ENTER_GRAVEYARD . owner == abi . source . owner
	
	ability:TRIGGERED_ABILITY . effect:ZONE-CHANGE . object == abi . source
	ability:TRIGGERED_ABILITY . effect:ZONE-CHANGE . event#1:LEAVE_GRAVEYARD . owner == abi . source . owner
	ability:TRIGGERED_ABILITY . effect:ZONE-CHANGE . event#2 == ENTER_EXILE
}

MGC_INSTRUCTIONS generic__creature_dies (object:o1)
{
	PLAYER p_1 = get_owner (o_1);
	ZONE z_1 = get_zone (zone-type:TYPE_GRAVEYARD, owner:p_1);
	
	EVENT e_1 == create_event (event-type:TYPE_OBJECT_LIFECYCLE, subevent-type:LEAVE_BATTLEFIELD, object:o_1);
	throw_event (event:e_1); [*2*]
	
	OBJECT o_2 = create_object (from-object:o_1, owner:p_1);
	destroy_object (object:o_1);
	
	EVENT e_2 == create_event (event-type:TYPE_OBJECT_LIFECYCLE, subevent-type:ENTER_GRAVEYARD, zone:z_1, object:o_2);
	throw_event (event:e_2); [*3*]
}

MGC_INSTRUCTIONS compiled__abi_effect (compiled__abi_ability:a_11)
{
	OBJECT o_11 = get_source (ability:a_11);
	
	PLAYER p_11 = get_owner (o_11);
	ZONE z_11 = get_zone (zone-type:TYPE_GRAVEYARD, owner:p_11);
	
	EVENT e_11 == create_event (event-type:TYPE_OBJECT_LIFECYCLE, subevent-type:LEAVE_GRAVEYARD, zone:z_11, object:o_11);
	throw_game_event (event:e_11); [*6*]
	
	OBJECT o_12 = create_object (from-object:o_11, owner:p_11);
	destroy_object (object:o_11);
	
	EVENT e_12 == create_event (event-type:TYPE_OBJECT_LIFECYCLE, subevent-type:ENTER_EXILE, object:o_12);
	throw_game_event (event:e_12); [*7*]
}

MVM_MODULE event_handler
loop (forever)
{
	wait_until_next_game_event_is_thrown();
	EVENT e = catch_next_game_event();
	
	test (e.event-type + subevent-type)
	{
		...
		if (TYPE_STATE_BASED_ACTION + DESTROY_CREATURE) then
		{
			OBJECT c = get_dying_creature (event:e);
			
			INSTRUCTIONS is = load_instructions_for___generic__creature_dies ();
			execute_effect (instructions:is, data:c); [*1*]
		}
		...
		if (TYPE_OBJECT_LIFECYCLE + ENTER_GRAVEYARD) then
		{
			OBJECTS ts = find_all_applicable_triggers_for_event (event:e);
			loop (OBJECT t IN ts)
			{
				push_onto_stack (object:t); [*4*]
			}
		}
		...
	}
}

MVM_MODULE stack_resolver
loop (forever)
{
	wait_until_top_of_stack_is_ready_to_resolve();
	OBJECT t = pop_top_from_stack();
	
	INSTRUCTIONS is = load_instructions_for___compiled__effect (object:t);
	execute_effect (instructions:is, data:t); [*5*]
}



back to: Card Pools