akaps / hanabi_ai

AI competition of the card game Hanabi, where the best AI is measured as the most cooperative and contributes to the highest scoring games
MIT License
1 stars 2 forks source link

Implement the If (Rule), Then (Rule), Else (Rule) Action #60

Closed akaps closed 6 years ago

akaps commented 6 years ago

This one's a doozy

Description of the action from Evaluating and Modelling Hanabi-Playing Agents.pdf:

Takes a Boolean λ expression and either one or two rules. The first rule will be used if the λ evaluates to true. If it is false, and a second rule was provided, then that will be used instead.

C-Saunders commented 6 years ago

Does this need to be an actual rule/action function like discard_oldest_first or tell_randomly, or can implementors set up their own conditionals using regular conditional logic without the need for this?

I tend to think "in types" and tried to map out the types for this, which clarified it for me, I think.

Currently, it looks like the psuedo-code signature of actions is something like type Action: (player_id: number, game_info: GameInfo, seed: number) => Option<PlayerAction>

From what I can see, this can't fit that shape because it needs the predicate and argument(s) for said predicate, which can't fit into the current parameters.

It's very possible I'm thinking about this wrong, so please let me know if that's the case!

akaps commented 6 years ago

I thought you could pass functions as parameters. My first stab would have been type Action:(player_id: number, game_info: GameInfo, seed: number, condition: function(?), true_rule: Option<PlayerAction>, false_rule: Option<PlayerAction>) reading it looks pretty stupid, this just evaluates an expression and returns existing values. This concept should probably just be bot specific, right? It only gets interesting if the values in the PlayerAction can be variable, so you pass in functions to true_rule and false_rule? Meh...

C-Saunders commented 6 years ago

I thought you could pass functions as parameters.

You can, indeed! Since functions are objects, you can do that, as well as fun stuff like this, which could be a way a bot implementation could choose to do a conditional invocation:

... some rules ...
(true_rule_fn if condition else false_rule_fn)(player_id, game_info, seed)
... some rules ...

The alternative invocation style seems to me to be something like this:

... some rules ...
conditional_rule(player_id, game_info, seed, predicate, true_rule_fn, false_rule_fn)
... some rules ...

Where true_rule_fn and false_rule_fn are functions of the Action type I described above, and predicate is a function with a signature maybe like: (game_info: GameInfo, seed: number) => boolean, since it will only have the game_info (and player_id) to use to make decisions.

I was originally thinking that this rule would be a rule factory- returning a function with the same signature as a Rule, but that didn't seem like it would work. I think I didn't explain that that was my thinking in my first reply.

It only gets interesting if the values in the PlayerAction can be variable

Would the PlayerActions returned by any rule need to have essentially the same shape in order to be legal player actions?

akaps commented 6 years ago

Sounds like we are more or less in agreement. The action will evaluate if/then/else, not create rules. If this action was implemented in the utils module, I imagine it would look something like the second signature.

Thinking about it now, does that mean this function is just an if block?

def if_then(player_id, game_info, predicate, true_rule, false_rule):
    if predicate:
        return true_rule
    else:
        return false_rule

There doesn't seem to be much value in that. I'm thinking we shouldn't make this function. Makes sense?

akaps commented 6 years ago

Separate idea/clarification for the last point

Would the PlayerActions returned by any rule need to have essentially the same shape in order to be legal player actions?

Yes, hanabi_player describes the 4 different types of dictionaries do_turn is expected to return. For instance, playing a card always is

{'play_type' : 'play', 'card' : <some number>}

What I meant by variable was that the card index, color or rank disclosed could be subject to change. Imagine a rule that does a disclose rank, but decides which rank within the function.

Dictionaries isn't the best contract, and we could probably improve it (and game_info for the same reason), but I don't think that's what you were bringing up

akaps commented 6 years ago

Gonna close this issue. Bots can do the if/else logic themselves and I don't think you lose anything/have too much repeated code