/* Copyright 2002 Ben Blum, Christian Shelton
 *
 * This file is part of GameTracer.
 *
 * GameTracer is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * GameTracer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GameTracer; if not, write to the Free Software Foundation, 
 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "cmatrix.h"
#include "nfgame.h"

nfgame::nfgame(int numPlayers, int *actions, const cvector &payoffs) : gnmgame(numPlayers, actions), payoffs(payoffs) {
  blockSize = new int[numPlayers + 1];
  blockSize[0] = 1;
  for(int i = 1; i <= numPlayers; i++) {
    blockSize[i] = blockSize[i-1]*actions[i-1];
  }
}

nfgame::~nfgame() {
  delete[] blockSize;
}

int nfgame::findIndex(int player, int *s) {
  int i, retIndex=player * blockSize[numPlayers];
  for(i = 0; i < numPlayers; i++)
    retIndex += blockSize[i] * s[i];
  return retIndex;
}

double nfgame::getMixedPayoff(int player, cvector &s) {
  double m[blockSize[numPlayers]];
  memcpy(m, payoffs.values() + player * blockSize[numPlayers], blockSize[numPlayers]*sizeof(double));
  return localPayoff(s, m, numPlayers);
}

void nfgame::payoffMatrix(cmatrix &dest, cvector &s, double fuzz) {
  int rown, coln, rowi, coli;
  double fuzzcount;
  double m[blockSize[numPlayers]];
  double local[maxActions*maxActions];
  for(rown = 0; rown < numPlayers; rown++) {
    for(coln = 0; coln < numPlayers; coln++) {
      if(rown == coln) {
	fuzzcount = fuzz;
	for(rowi=firstAction(rown); rowi < lastAction(rown); rowi++) {
	  for(coli=firstAction(coln); coli < lastAction(coln); coli++) {
	    dest[rowi][coli]=fuzzcount;
	    fuzzcount += fuzz;
	  }
	}
      } else {
	// set m to be the payoffs for player rown
	memcpy(m, payoffs.values() + rown * blockSize[numPlayers], blockSize[numPlayers] * sizeof(double));
	localPayoffMatrix(local, rown, coln, s, m, numPlayers-1);
	for(rowi = firstAction(rown); rowi < lastAction(rown); rowi++) {
	  for(coli = firstAction(coln); coli < lastAction(coln); coli++) {
	    if(rown > coln) {
	      dest[rowi][coli] = *(local + (rowi - firstAction(rown))*actions[coln] + (coli - firstAction(coln)));
	    } else {
	      dest[rowi][coli] = *(local + (coli - firstAction(coln))*actions[rown] + (rowi - firstAction(rown)));
	    }
	  }
	}
      }
    }
  }
}


//assumes m = memcpy(m, payoffs + blockSize[numPlayers] * player1, blockSize[numPlayers]*sizeof(double)), player1 != player2
//i.e. m points to payoff cmatrix for the desired player

void nfgame::localPayoffMatrix(double *dest, int player1, int player2, cvector &s, double *m, int n) {
  int i;
  if(player1 == n) {
    for(i = 0; i < actions[player1]; i++) {
      localPayoffVector(dest+i*actions[player2], player2, s, m+i*blockSize[player1], n-1);
    }
  } else if(player2 == n) {
    for(i = 0; i < actions[player2]; i++) {
      localPayoffVector(dest+i*actions[player1], player1, s, m+i*blockSize[player2], n-1);
    }
  } else {
    m = scaleMatrix(s, m, n);
    localPayoffMatrix(dest, player1, player2, s, m, n-1);
  }
}

double *nfgame::scaleMatrix(cvector &s, double *m, int n) {
  int i,j, curbase, newbase = -1;
  double scale;
  for(i = 0; i < actions[n]; i++) {
    if(s[i+firstAction(n)] > 0.0) {
      scale = s[i+firstAction(n)];
      curbase = i*blockSize[n];
      if(newbase < 0) {
	newbase = curbase;
	for(j = curbase; j < curbase+blockSize[n]; j++) {
	  m[j] *= scale;
	}
      } else {
	for(j = 0; j < blockSize[n]; j++) {
	  m[newbase + j] += scale * m[curbase+j];
	}
      }
    }
  }
  return m+newbase;
}

void nfgame::localPayoffVector(double *dest, int player, cvector &s, double *m, int n) {
  if(player == n) {
    for(int i = 0; i < actions[player]; i++) {
      dest[i] = localPayoff(s, m+i*blockSize[player], n-1);
    }
  } else {
    m = scaleMatrix(s, m, n);
    localPayoffVector(dest, player, s, m, n-1);
  }
}

double nfgame::localPayoff(cvector &s, double *m, int n) {
  if(n < 0)
    return *m;
  else {
    m = scaleMatrix(s, m, n);
    return localPayoff(s, m, n-1);
  }
}


syntax highlighted by Code2HTML, v. 0.9.1