<commit_before>package ostinato.chess.ai

import ostinato.chess.core._
import ostinato.core.Ai

case class ChessBasicAi(player: ChessPlayer, debug: Boolean = false, seed: Option[Long] = None)
    extends Ai[ChessBoard, ChessAction, ChessPiece, ChessPlayer, ChessRules, ChessGame](player, seed) {

  override def nextAction(game: ChessGame)(implicit rules: ChessRules = ChessRules.default): Option[ChessAction] = {
    val actions = game.board.actionStream.force.toSeq
    val options = actions map (action ⇒ (action, alphabeta(game.board.doAction(action).get, action)))

    if (debug)
      options foreach println

    Some(options.sortWith(sort).head._1)
  }

  def sort(a: (ChessAction, Long), b: (ChessAction, Long)) = (a, b) match {
    case _ if a._1.isCheckmate => true
    case _ if b._1.isCheckmate => false
    case _ if a._2 > b._2 => true
    case _ if a._2 < b._2 => false
    case ((ac: CapturePromoteAction, _), (_, _)) => true
    case ((_, _), (bc: CapturePromoteAction, _)) => false
    case ((ac: PromoteAction, _), (_, _)) => true
    case ((_, _), (bc: PromoteAction, _)) => false
    case ((ac: CaptureAction, _), (_, _)) => true
    case ((_, _), (bc: CaptureAction, _)) => false
    case ((ac: EnPassantCaptureAction, _), (_, _)) => true
    case ((_, _), (bc: EnPassantCaptureAction, _)) => false
    case ((ac: CastlingAction, _), (_, _)) => true
    case ((_, _), (bc: CastlingAction, _)) => false
    case _ => a._2 > b._2
  }

  def alphabeta(board: ChessBoard, action: ChessAction, depth: Int = 1, alpha: Long = -Long.MaxValue, beta: Long = Long.MaxValue): Long = {
    var a = alpha
    var b = beta

    if (depth == 0) {
      val value = evaluate(board, action)
      value
    } else {
      if (player != action.turn) {
        var v = -Long.MaxValue
        try {
          board.actionStream.foreach { newAction ⇒
            v = math.max(v, alphabeta(board.doAction(newAction).get, newAction, depth - 1, a, b))
            a = math.max(a, v)
            if (b <= a) throw new RuntimeException
          }
          v
        } catch { case _: Throwable => v }
      } else {
        var v = Long.MaxValue
        try {
          board.actionStream.foreach { newAction ⇒
            v = math.min(v, alphabeta(board.doAction(newAction).get, newAction, depth - 1, a, b))
            b = math.min(b, v)
            if (b <= a) throw new RuntimeException
          }
          v
        } catch { case _: Throwable => v }
      }
    }
  }

  private def sign(owner: ChessPlayer) = if (owner == player) 1 else -1

  private def materialValue(piece: ChessPiece) = piece match {
    case p: ♛ ⇒ 9
    case p: ♚ ⇒ 0
    case p: ♝ ⇒ 3
    case p: ♞ ⇒ 3
    case p: ♜ ⇒ 5
    case p: ♟ ⇒ 1
  }

  private def isInMiddle(piece: ChessPiece): Boolean =
    piece.pos.x >= 2 && piece.pos.x <= 5 && piece.pos.y >= 3 && piece.pos.y <= 4

  private def int(b: Boolean) = if (b) 1 else 0

  private def evaluate(board: ChessBoard, action: ChessAction): Long = {
    action match {

      // PRIORITY #1: GAME END
      case a: LoseAction ⇒ Long.MaxValue * sign(action.turn.enemy)
      case _ ⇒
        if (action.isCheckmate) {
          Long.MaxValue * sign(action.turn)
        }<commit_msg>Removed the quick solution for pruning based on Exceptions.<commit_after>package ostinato.chess.ai

import ostinato.chess.core._
import ostinato.core.Ai

case class ChessBasicAi(player: ChessPlayer, debug: Boolean = false, seed: Option[Long] = None)
    extends Ai[ChessBoard, ChessAction, ChessPiece, ChessPlayer, ChessRules, ChessGame](player, seed) {

  override def nextAction(game: ChessGame)(implicit rules: ChessRules = ChessRules.default): Option[ChessAction] = {
    val actions = game.board.actionStream.force.toSeq
    val options = actions map (action ⇒ (action, alphabeta(game.board.doAction(action).get, action)))

    if (debug)
      options foreach println

    Some(options.sortWith(sort).head._1)
  }

  def sort(a: (ChessAction, Long), b: (ChessAction, Long)) = (a, b) match {
    case _ if a._1.isCheckmate => true
    case _ if b._1.isCheckmate => false
    case _ if a._2 > b._2 => true
    case _ if a._2 < b._2 => false
    case ((ac: CapturePromoteAction, _), (_, _)) => true
    case ((_, _), (bc: CapturePromoteAction, _)) => false
    case ((ac: PromoteAction, _), (_, _)) => true
    case ((_, _), (bc: PromoteAction, _)) => false
    case ((ac: CaptureAction, _), (_, _)) => true
    case ((_, _), (bc: CaptureAction, _)) => false
    case ((ac: EnPassantCaptureAction, _), (_, _)) => true
    case ((_, _), (bc: EnPassantCaptureAction, _)) => false
    case ((ac: CastlingAction, _), (_, _)) => true
    case ((_, _), (bc: CastlingAction, _)) => false
    case _ => a._2 > b._2
  }

  def alphabeta(board: ChessBoard, action: ChessAction, depth: Int = 1, alpha: Long = -Long.MaxValue, beta: Long = Long.MaxValue): Long = {
    var a = alpha
    var b = beta

    if (depth == 0) {
      val value = evaluate(board, action)
      value
    } else {
      if (player != action.turn) {
        var v = -Long.MaxValue
          board.actionStream.foreach { newAction ⇒
            v = math.max(v, alphabeta(board.doAction(newAction).get, newAction, depth - 1, a, b))
            a = math.max(a, v)
            if (b <= a) return v
          }
          v
      } else {
        var v = Long.MaxValue
          board.actionStream.foreach { newAction ⇒
            v = math.min(v, alphabeta(board.doAction(newAction).get, newAction, depth - 1, a, b))
            b = math.min(b, v)
            if (b <= a) return v
          }
          v
      }
    }
  }

  private def sign(owner: ChessPlayer) = if (owner == player) 1 else -1

  private def materialValue(piece: ChessPiece) = piece match {
    case p: ♛ ⇒ 9
    case p: ♚ ⇒ 0
    case p: ♝ ⇒ 3
    case p: ♞ ⇒ 3
    case p: ♜ ⇒ 5
    case p: ♟ ⇒ 1
  }

  private def isInMiddle(piece: ChessPiece): Boolean =
    piece.pos.x >= 2 && piece.pos.x <= 5 && piece.pos.y >= 3 && piece.pos.y <= 4

  private def int(b: Boolean) = if (b) 1 else 0

  private def evaluate(board: ChessBoard, action: ChessAction): Long = {
    action match {

      // PRIORITY #1: GAME END
      case a: LoseAction ⇒ Long.MaxValue * sign(action.turn.enemy)
      case _ ⇒
        if (action.isCheckmate) {
          Long.MaxValue * sign(action.turn)
        }
{'fraction_non_alphanumeric': 0.1420670037926675, 'fraction_numerical': 0.008849557522123894, 'mean_word_length': 2.473655323819978, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7484295', 'n_tokens_mistral': 2260, 'n_tokens_neox': 2186, 'n_words': 608}