// File: ATOMIC-LICHESS[P]ATOMKRAFT/material.cpp
// Function: MaterialInfoTable::get_material_info(Position const&) const
MaterialInfo* MaterialInfoTable::get_material_info(const Position& pos) const {

  Key key = pos.get_material_key();
  MaterialInfo* mi = probe(key);

  // If mi->key matches the position's material hash key, it means that we
  // have analysed this material configuration before, and we can simply
  // return the information we found the last time instead of recomputing it.
  if (mi->key == key)
      return mi;

  // Initialize MaterialInfo entry
  memset(mi, 0, sizeof(MaterialInfo));
  mi->key = key;
  mi->factor[WHITE] = mi->factor[BLACK] = (uint8_t)SCALE_FACTOR_NORMAL;

  // Store game phase
  mi->gamePhase = MaterialInfoTable::game_phase(pos);
  
  
  STARTNEW
  // endgame scaling
  // calculated before the the special evaluation because the special evaluation
  // may return VALUE_NONE and we had no scaling...
  
  int pcount_w = pos.piece_count(WHITE, PAWN);
  int pcount_b = pos.piece_count(BLACK, PAWN);
  Value npm_w = pos.non_pawn_material(WHITE);
  Value npm_b = pos.non_pawn_material(BLACK);
  
  if (pcount_w - pcount_b == 1) {
	  // white is a pawn up
	  
	  if (npm_w == VALUE_ZERO) {
		  // but has no material other than pawns
		  if (npm_b > 0 && npm_b <= RookValueMidgame) {
			  // if black has a knight, bishop or rook the game is still hard to win for black
			  mi->factor[BLACK] = 32;
		  }
	  }
	  
  } else if (pcount_b - pcount_w == 1) {
	  // black is a pawn up
	  if (npm_b == VALUE_ZERO) {
		  // but has no material other than pawns
		  if (npm_w > 0 && npm_w <= RookValueMidgame) {
			  // if white has a knight, bishop or rook the game is still hard to win for white
			  mi->factor[WHITE] = 32;
		  }
	  }
  } else if (pcount_w == pcount_b) {
	  // both side have the same number of pawns
	  
	  if (   npm_b == VALUE_ZERO 
		  && pos.piece_count(WHITE, BISHOP) == 1 
		  && npm_w <= KnightValueMidgame) {
		  // but white is up a bishop, it's still very hard to win for white in most situations
		  mi->factor[WHITE] = 16;
	  } else if (   npm_w == VALUE_ZERO 
			     && pos.piece_count(BLACK, BISHOP) == 1 
			     && npm_b <= KnightValueMidgame) {
		  // but black is up a bishop, it's still very hard to win for black in most situations
		  mi->factor[BLACK] = 16;
	  }
	  
  }
  
  ENDNEW
  

  // Let's look if we have a specialized evaluation function for this
  // particular material configuration. First we look for a fixed
  // configuration one, then a generic one if previous search failed.
  if ((mi->evaluationFunction = funcs->get<EndgameBase<Value> >(key)) != NULL) {
      return mi;
  }
  
  
  if (is_KXK<WHITE>(pos))
  {
      mi->evaluationFunction = &EvaluateKXK[WHITE];
      return mi;
  }

  if (is_KXK<BLACK>(pos))
  {
      mi->evaluationFunction = &EvaluateKXK[BLACK];
      return mi;
  }
  
  

  
  
  
  NEW // old: scaling functions, of course they do not apply for atomic chess 
  
  STARTOLD
  if (!pos.pieces(PAWN) && !pos.pieces(ROOK) && !pos.pieces(QUEEN))
  {
	  
	  mi->evaluationFunction = &EvaluateKmmKm[WHITE];
      // Minor piece endgame with at least one minor piece per side and
      // no pawns. Note that the case KmmK is already handled by KXK.
      assert((pos.pieces(KNIGHT, WHITE) | pos.pieces(BISHOP, WHITE)));
      assert((pos.pieces(KNIGHT, BLACK) | pos.pieces(BISHOP, BLACK)));

      if (   pos.piece_count(WHITE, BISHOP) + pos.piece_count(WHITE, KNIGHT) <= 2
          && pos.piece_count(BLACK, BISHOP) + pos.piece_count(BLACK, KNIGHT) <= 2)
      {
          mi->evaluationFunction = &EvaluateKmmKm[WHITE];
          return mi;
      }
  }
  
  
  

  // OK, we didn't find any special evaluation function for the current
  // material configuration. Is there a suitable scaling function?
  //
  // We face problems when there are several conflicting applicable
  // scaling functions and we need to decide which one to use.
  EndgameBase<ScaleFactor>* sf;

  if ((sf = funcs->get<EndgameBase<ScaleFactor> >(key)) != NULL)
  {
      mi->scalingFunction[sf->color()] = sf;
      return mi;
  }

  // Generic scaling functions that refer to more then one material
  // distribution. Should be probed after the specialized ones.
  // Note that these ones don't return after setting the function.
  if (is_KBPsKs<WHITE>(pos))
      mi->scalingFunction[WHITE] = &ScaleKBPsK[WHITE];

  if (is_KBPsKs<BLACK>(pos))
      mi->scalingFunction[BLACK] = &ScaleKBPsK[BLACK];

  if (is_KQKRPs<WHITE>(pos))
      mi->scalingFunction[WHITE] = &ScaleKQKRPs[WHITE];

  else if (is_KQKRPs<BLACK>(pos))
      mi->scalingFunction[BLACK] = &ScaleKQKRPs[BLACK];

  Value npm_w = pos.non_pawn_material(WHITE);
  Value npm_b = pos.non_pawn_material(BLACK);

  if (npm_w + npm_b == VALUE_ZERO)
  {
      if (pos.piece_count(BLACK, PAWN) == 0)
      {
          assert(pos.piece_count(WHITE, PAWN) >= 2);
          mi->scalingFunction[WHITE] = &ScaleKPsK[WHITE];
      }
      else if (pos.piece_count(WHITE, PAWN) == 0)
      {
          assert(pos.piece_count(BLACK, PAWN) >= 2);
          mi->scalingFunction[BLACK] = &ScaleKPsK[BLACK];
      }
      else if (pos.piece_count(WHITE, PAWN) == 1 && pos.piece_count(BLACK, PAWN) == 1)
      {
          // This is a special case because we set scaling functions
          // for both colors instead of only one.
          mi->scalingFunction[WHITE] = &ScaleKPKP[WHITE];
          mi->scalingFunction[BLACK] = &ScaleKPKP[BLACK];
      }
  }

  // No pawns makes it difficult to win, even with a material advantage
  if (pos.piece_count(WHITE, PAWN) == 0 && npm_w - npm_b <= BishopValueMidgame)
  {
      mi->factor[WHITE] = uint8_t
      (npm_w == npm_b || npm_w < RookValueMidgame ? 0 : NoPawnsSF[Min(pos.piece_count(WHITE, BISHOP), 2)]);
  }

  if (pos.piece_count(BLACK, PAWN) == 0 && npm_b - npm_w <= BishopValueMidgame)
  {
      mi->factor[BLACK] = uint8_t
      (npm_w == npm_b || npm_b < RookValueMidgame ? 0 : NoPawnsSF[Min(pos.piece_count(BLACK, BISHOP), 2)]);
  }

  // Compute the space weight
  if (npm_w + npm_b >= 2 * QueenValueMidgame + 4 * RookValueMidgame + 2 * KnightValueMidgame)
  {
      int minorPieceCount =  pos.piece_count(WHITE, KNIGHT) + pos.piece_count(WHITE, BISHOP)
                           + pos.piece_count(BLACK, KNIGHT) + pos.piece_count(BLACK, BISHOP);

      mi->spaceWeight = minorPieceCount * minorPieceCount;
  }
  ENDOLD

  // Evaluate the material imbalance. We use PIECE_TYPE_NONE as a place holder
  // for the bishop pair "extended piece", this allow us to be more flexible
  // in defining bishop pair bonuses.
  const int pieceCount[2][8] = {
  { pos.piece_count(WHITE, BISHOP) > 1, pos.piece_count(WHITE, PAWN), pos.piece_count(WHITE, KNIGHT),
    pos.piece_count(WHITE, BISHOP)    , pos.piece_count(WHITE, ROOK), pos.piece_count(WHITE, QUEEN) },
  { pos.piece_count(BLACK, BISHOP) > 1, pos.piece_count(BLACK, PAWN), pos.piece_count(BLACK, KNIGHT),
    pos.piece_count(BLACK, BISHOP)    , pos.piece_count(BLACK, ROOK), pos.piece_count(BLACK, QUEEN) } };

  mi->value = int16_t((imbalance<WHITE>(pieceCount) - imbalance<BLACK>(pieceCount)) / 16);
  return mi;
}

// Assembly:
subq $0xb8, %rsp
movq %rdi, 0xa8(%rsp)
movq %rsi, 0xa0(%rsp)
movq 0xa8(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0xa0(%rsp), %rdi
callq 0x1c6e0
movq 0x38(%rsp), %rdi
movq %rax, 0x98(%rsp)
movq 0x98(%rsp), %rsi
callq 0x2b2d0
movq %rax, 0x90(%rsp)
movq 0x90(%rsp), %rax
movq (%rax), %rax
cmpq 0x98(%rsp), %rax
jne 0x2a8ed
movq 0x90(%rsp), %rax
movq %rax, 0xb0(%rsp)
jmp 0x2ada9
movq 0x90(%rsp), %rdi
xorl %esi, %esi
movl $0x30, %edx
callq 0x6280
movq 0x98(%rsp), %rcx
movq 0x90(%rsp), %rax
movq %rcx, (%rax)
movq 0x90(%rsp), %rax
movb $0x40, 0xb(%rax)
movq 0x90(%rsp), %rax
movb $0x40, 0xa(%rax)
movq 0xa0(%rsp), %rdi
callq 0x2adc0
movl %eax, %ecx
movq 0x90(%rsp), %rax
movl %ecx, 0x2c(%rax)
movq 0xa0(%rsp), %rdi
xorl %esi, %esi
movl $0x1, %edx
callq 0x164c0
movl %eax, 0x8c(%rsp)
movq 0xa0(%rsp), %rdi
movl $0x1, %edx
movl %edx, %esi
callq 0x164c0
movl %eax, 0x88(%rsp)
movq 0xa0(%rsp), %rdi
xorl %esi, %esi
callq 0x298e0
movl %eax, 0x84(%rsp)
movq 0xa0(%rsp), %rdi
movl $0x1, %esi
callq 0x298e0
movl %eax, 0x80(%rsp)
movl 0x8c(%rsp), %eax
subl 0x88(%rsp), %eax
cmpl $0x1, %eax
jne 0x2a9f7
cmpl $0x0, 0x84(%rsp)
jne 0x2a9f2
cmpl $0x0, 0x80(%rsp)
jle 0x2a9f0
movl 0x80(%rsp), %eax
leaq 0x41b90(%rip), %rcx     # 0x6c570
cmpl (%rcx), %eax
jg 0x2a9f0
movq 0x90(%rsp), %rax
movb $0x20, 0xb(%rax)
jmp 0x2a9f2
jmp 0x2aae6
movl 0x88(%rsp), %eax
subl 0x8c(%rsp), %eax
cmpl $0x1, %eax
jne 0x2aa43
cmpl $0x0, 0x80(%rsp)
jne 0x2aa3e
cmpl $0x0, 0x84(%rsp)
jle 0x2aa3c
movl 0x84(%rsp), %eax
leaq 0x41b44(%rip), %rcx     # 0x6c570
cmpl (%rcx), %eax
jg 0x2aa3c
movq 0x90(%rsp), %rax
movb $0x20, 0xa(%rax)
jmp 0x2aa3e
jmp 0x2aae4
movl 0x8c(%rsp), %eax
cmpl 0x88(%rsp), %eax
jne 0x2aae2
cmpl $0x0, 0x80(%rsp)
jne 0x2aa9a
movq 0xa0(%rsp), %rdi
xorl %esi, %esi
movl $0x3, %edx
callq 0x164c0
cmpl $0x1, %eax
jne 0x2aa9a
movl 0x84(%rsp), %eax
leaq 0x41ad8(%rip), %rcx     # 0x6c560
cmpl (%rcx), %eax
jg 0x2aa9a
movq 0x90(%rsp), %rax
movb $0x10, 0xa(%rax)
jmp 0x2aae0
cmpl $0x0, 0x84(%rsp)
jne 0x2aade
movq 0xa0(%rsp), %rdi
movl $0x1, %esi
movl $0x3, %edx
callq 0x164c0
cmpl $0x1, %eax
jne 0x2aade
movl 0x80(%rsp), %eax
leaq 0x41a92(%rip), %rcx     # 0x6c560
cmpl (%rcx), %eax
jg 0x2aade
movq 0x90(%rsp), %rax
movb $0x10, 0xb(%rax)
jmp 0x2aae0
jmp 0x2aae2
jmp 0x2aae4
jmp 0x2aae6
movq 0x38(%rsp), %rax
movq 0x10(%rax), %rdi
movq 0x98(%rsp), %rsi
callq 0x1b0d0
movq 0x90(%rsp), %rcx
movq %rax, 0x10(%rcx)
cmpq $0x0, %rax
je 0x2ab23
movq 0x90(%rsp), %rax
movq %rax, 0xb0(%rsp)
jmp 0x2ada9
movq 0xa0(%rsp), %rdi
callq 0x2aed0
testb $0x1, %al
jne 0x2ab36
jmp 0x2ab5e
movq 0x90(%rsp), %rax
leaq 0x3b83cb(%rip), %rcx    # 0x3e2f10
movq %rcx, 0x10(%rax)
movq 0x90(%rsp), %rax
movq %rax, 0xb0(%rsp)
jmp 0x2ada9
movq 0xa0(%rsp), %rdi
callq 0x2af30
testb $0x1, %al
jne 0x2ab71
jmp 0x2ab9d
movq 0x90(%rsp), %rax
leaq 0x3b8390(%rip), %rcx    # 0x3e2f10
addq $0x10, %rcx
movq %rcx, 0x10(%rax)
movq 0x90(%rsp), %rax
movq %rax, 0xb0(%rsp)
jmp 0x2ada9
movq 0xa0(%rsp), %rdi
xorl %esi, %esi
movl $0x3, %edx
callq 0x164c0
cmpl $0x1, %eax
setg %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, 0x40(%rsp)
movq 0xa0(%rsp), %rdi
xorl %esi, %esi
movl $0x1, %edx
callq 0x164c0
movl %eax, 0x44(%rsp)
movq 0xa0(%rsp), %rdi
xorl %esi, %esi
movl $0x2, %edx
callq 0x164c0
movl %eax, 0x48(%rsp)
movq 0xa0(%rsp), %rdi
xorl %esi, %esi
movl $0x3, %edx
callq 0x164c0
movl %eax, 0x4c(%rsp)
movq 0xa0(%rsp), %rdi
xorl %esi, %esi
movl $0x4, %edx
callq 0x164c0
movl %eax, 0x50(%rsp)
movq 0xa0(%rsp), %rdi
xorl %esi, %esi
movl $0x5, %edx
callq 0x164c0
movl %eax, 0x54(%rsp)
leaq 0x40(%rsp), %rax
addq $0x18, %rax
leaq 0x40(%rsp), %rcx
addq $0x20, %rcx
movq %rcx, 0x28(%rsp)
movq %rax, 0x30(%rsp)
movq 0x30(%rsp), %rax
movq 0x28(%rsp), %rcx
movl $0x0, (%rax)
addq $0x4, %rax
cmpq %rcx, %rax
movq %rax, 0x30(%rsp)
jne 0x2ac54
leaq 0x40(%rsp), %rax
addq $0x20, %rax
movq %rax, 0x10(%rsp)
movq 0xa0(%rsp), %rdi
movl $0x1, %esi
movl $0x3, %edx
callq 0x164c0
cmpl $0x1, %eax
setg %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, 0x60(%rsp)
movq 0xa0(%rsp), %rdi
movl $0x1, %edx
movl %edx, %esi
callq 0x164c0
movl %eax, 0x64(%rsp)
movq 0xa0(%rsp), %rdi
movl $0x1, %esi
movl $0x2, %edx
callq 0x164c0
movl %eax, 0x68(%rsp)
movq 0xa0(%rsp), %rdi
movl $0x1, %esi
movl $0x3, %edx
callq 0x164c0
movl %eax, 0x6c(%rsp)
movq 0xa0(%rsp), %rdi
movl $0x1, %esi
movl $0x4, %edx
callq 0x164c0
movl %eax, 0x70(%rsp)
movq 0xa0(%rsp), %rdi
movl $0x1, %esi
movl $0x5, %edx
callq 0x164c0
movq 0x10(%rsp), %rcx
movl %eax, 0x74(%rsp)
movq %rcx, %rax
addq $0x18, %rax
addq $0x20, %rcx
movq %rcx, 0x18(%rsp)
movq %rax, 0x20(%rsp)
movq 0x20(%rsp), %rax
movq 0x18(%rsp), %rcx
movl $0x0, (%rax)
addq $0x4, %rax
cmpq %rcx, %rax
movq %rax, 0x20(%rsp)
jne 0x2ad44
leaq 0x40(%rsp), %rdi
callq 0x2b300
movl %eax, 0xc(%rsp)
leaq 0x40(%rsp), %rdi
callq 0x2b450
movl %eax, %ecx
movl 0xc(%rsp), %eax
subl %ecx, %eax
movl $0x10, %ecx
cltd
idivl %ecx
movw %ax, %cx
movq 0x90(%rsp), %rax
movw %cx, 0x8(%rax)
movq 0x90(%rsp), %rax
movq %rax, 0xb0(%rsp)
movq 0xb0(%rsp), %rax
addq $0xb8, %rsp
retq
nopl (%rax)