Skip to content

Instantly share code, notes, and snippets.

@tylorahn
Last active August 29, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tylorahn/877d336a3a1344757463 to your computer and use it in GitHub Desktop.
Save tylorahn/877d336a3a1344757463 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameProject
{
class Program
{
static void Main(string[] args)
{
var game = new TwoPlayerZeroSumGame();
Console.WriteLine(game.GetPayoffMatrix());
Console.ReadLine();
}
}
/// <summary>
/// I have tried to make the class applicable for more general games (to be specific, two player zero-sum game).
/// This perhaps added unnecessary details, but who knows if I might need to do similar computation in future.
/// For instance, for this particular Kuhn poker game, PlayerType is not really useful.
/// </summary>
public class TwoPlayerZeroSumGame
{
/// <summary>
/// Returns the Player 1's payoff matrix in string format.
/// </summary>
public string GetPayoffMatrix()
{
string matrix = "Player1Matrix,";
var player1Strategies = GetAllPlayer1Strategies();
var player2Strategies = GetAllPlayer2Strategies();
// Add a header.
foreach (var player2Strategy in player2Strategies)
matrix += player2Strategy.ToString() + ",";
matrix += Environment.NewLine;
// Add each row.
foreach (var player1Strategy in player1Strategies)
{
var row = player1Strategy.ToString() + ",";
foreach (var player2Strategy in player2Strategies)
row += GetExpectedUtility(player1Strategy, player2Strategy).ToString("F2") + ",";
matrix += row + Environment.NewLine;
}
return matrix;
}
public List<Strategy> GetAllPlayer1Strategies()
{
var strategies = new List<Strategy>();
var firstMoves = new List<char>() { 'C', 'B' };
var secondMoves = new List<char>() { 'F', 'C' };
foreach (var firstJ in firstMoves)
foreach (var firstQ in firstMoves)
foreach (var firstK in firstMoves)
foreach (var secondJ in secondMoves)
foreach (var secondQ in secondMoves)
foreach (var secondK in secondMoves)
{
var notation =
string.Format("{0}{1}{2}{3}{4}{5}",
firstJ, firstQ, firstK, secondJ, secondQ, secondK);
// If Player 1 plays B in the first round, he has no option on the second round(X).
for (int i = 0; i < 3; i++)
if (notation[i] == 'B')
notation = Utility.ReplaceAt(notation, i + 3, 'X');
var strategy = new Strategy(PlayerType.Player1, notation);
if (!strategies.Contains(strategy))
strategies.Add(strategy);
}
return strategies;
}
public List<Strategy> GetAllPlayer2Strategies()
{
var strategies = new List<Strategy>();
var firstMoves = new List<char>() { 'F', 'C' };
var secondMoves = new List<char>() { 'C', 'B' };
foreach (var firstJ in firstMoves)
foreach (var firstQ in firstMoves)
foreach (var firstK in firstMoves)
foreach (var secondJ in secondMoves)
foreach (var secondQ in secondMoves)
foreach (var secondK in secondMoves)
{
var notation =
string.Format("{0}{1}{2}{3}{4}{5}",
firstJ, firstQ, firstK, secondJ, secondQ, secondK);
var strategy = new Strategy(PlayerType.Player2, notation);
strategies.Add(strategy);
}
return strategies;
}
/// <summary>
/// Returns the list of all states.
/// </summary>
public List<string> GetAllStates()
{
return new List<string>() { "KQ", "KJ", "QK", "QJ", "JK", "JQ" };
}
/// <summary>
/// Returns the probability that a given state is realized.
/// In Kuhn poker game, every state is always realized with the probability of 1/6.
/// </summary>
public double StateProbability(string state)
{
return (1d / 6);
}
/// <summary>
/// Returns the expected utility of player 1.
/// </summary>
public double GetExpectedUtility(Strategy myStrategy, Strategy otherStrategy)
{
double expectedUtility = 0;
var states = GetAllStates();
foreach (var state in states)
expectedUtility += StateProbability(state) * GetUtility(myStrategy, otherStrategy, state);
return expectedUtility;
}
/// <summary>
/// Returns the utility of player 1 according to the rule of a game.
/// </summary>
public double GetUtility(Strategy myStrategy, Strategy otherStrategy, string state)
{
if ((myStrategy.Response(state[0]))[0] == 'B')
if ((otherStrategy.Response(state[1]))[0] == 'F')
return 1;
else
if (Player1Wins(state[0], state[1]))
return 2;
else
return -2;
else
if ((otherStrategy.Response(state[1]))[1] == 'C')
if (Player1Wins(state[0], state[1]))
return 1;
else
return -1;
else
if ((myStrategy.Response(state[0]))[1] == 'F')
return -1;
else
if (Player1Wins(state[0], state[1]))
return 2;
else
return -2;
}
/// <summary>
/// Returns true if player 1 wins.
/// </summary>
public static bool Player1Wins(char player1State, char player2State)
{
return (StateToNum(player1State) > StateToNum(player2State));
}
/// <summary>
/// Returns a number according to state. J -> 0, Q -> 1, K -> 2.
/// </summary>
public static int StateToNum(char state)
{
switch (state)
{
case 'J':
return 0;
case 'Q':
return 1;
case 'K':
return 2;
default:
return -1;
}
}
}
public class Strategy
{
public readonly PlayerType PlayerType;
public readonly string Notation;
public Strategy(PlayerType playerType, string notation)
{
PlayerType = playerType;
Notation = notation;
}
/// <summary>
/// Returns response to the current state according to a strategy.
/// For this Kuhn poker game, if a strategy is CBCFXC and a given state is J, returns "CF"
/// where first letter represents his response on the first stage, the latter for the second stage.
/// </summary>
public string Response(char myState)
{
var stateNum = TwoPlayerZeroSumGame.StateToNum(myState);
var first = Notation[stateNum];
var second = Notation[stateNum + 3];
return string.Format("{0}{1}", first, second);
}
/// <summary>
/// Two strategies are equal if their notations are identical.
/// </summary>
public override bool Equals(object obj)
{
Strategy other = obj as Strategy;
if (obj == null)
return false;
return Notation == other.Notation;
}
public override int GetHashCode()
{
return this.Notation.GetHashCode();
}
public override string ToString()
{
return Notation;
}
}
public enum PlayerType
{
Player1,
Player2,
}
public static class Utility
{
public static string ReplaceAt(this string input, int index, char newChar)
{
char[] chars = input.ToCharArray();
chars[index] = newChar;
return new string(chars);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment