How to link Lightning Components using events inside a Lightning App Builder page?

Application-level events certainly are what Salesforce recommends for the use case of components that will be "App Builder siblings" and need to talk to one another.

I think you won't be able to limit which components see the event, but you can limit which ones respond to it. If I understand correctly your "pitcher" and "receiver" are independent components you expect an end-user to be able to put on a page together and talk to one another.

For the use case where the admin has put multiple groups on the same page, maybe you could put a string identifier field on the component (call it a name, channel, key, what have you) and expose it to App Builder via Design. Then you would instruct admins, if there will be more than one interacting pair, please fill in the identifiers in matching pairs/groups so it knows who's who. In terms of implementation, every event you fire could include the identifier as an attribute so you can check for it.

For the console use case, you could include lightning:workspaceAPI in the components. On init, use getEnclosingTabId() and hold onto that (returns false if not in console tab). When firing an event, pass a "tab ID" attribute. When catching it, verify both the tab ID and the other identifier match.

Reference: https://developer.salesforce.com/docs/atlas.en-us.api_console.meta/api_console/sforce_api_console_lightning_getEnclosingTabId.htm

If you find any other use cases not covered by these, then just consider, is there something unique that you can use (or provide) to determine whether an instance is the wrong recipient?