Advertisement
Guest User

Untitled

a guest
Dec 15th, 2019
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.08 KB | None | 0 0
  1. import java.lang.Integer.max
  2. import java.lang.Integer.min
  3. import java.util.*
  4.  
  5. typealias Point = Pair<Int, Int>
  6. typealias Matrix = Array<CharArray>
  7.  
  8. class TicTacToeGame {
  9. companion object {
  10. const val PLAYER_ONE_SYMBOL = 'X'
  11. const val PLAYER_TWO_SYMBOL = 'O'
  12. const val EMPTY_SPOT = '.'
  13. const val SIZE = 3
  14. const val WIN_VALUE = 777
  15. const val LOSE_VALUE = -777
  16. const val NO_WINNER = 0
  17. }
  18.  
  19. private val board: Matrix by lazy {
  20. Matrix(SIZE) { CharArray(SIZE) { EMPTY_SPOT } }
  21. }
  22.  
  23. private fun isMoveLeft(): Boolean {
  24. for (row in board) {
  25. if (row.contains(EMPTY_SPOT))
  26. return true
  27. }
  28. return false
  29. }
  30.  
  31. private fun Matrix.evaluateState(): Int {
  32. val playerOneWinningStreak = charArrayOf(PLAYER_ONE_SYMBOL, PLAYER_ONE_SYMBOL, PLAYER_ONE_SYMBOL)
  33. val playerTwoWinningStreak = charArrayOf(PLAYER_TWO_SYMBOL, PLAYER_TWO_SYMBOL, PLAYER_TWO_SYMBOL)
  34. for (row in this) {
  35. if (row.contentEquals(playerOneWinningStreak))
  36. return LOSE_VALUE
  37. if (row.contentEquals(playerTwoWinningStreak))
  38. return WIN_VALUE
  39. }
  40. for (col in 0 until SIZE) {
  41. this.map { it[col] }.toCharArray().also {
  42. if (it.contentEquals(playerOneWinningStreak))
  43. return LOSE_VALUE
  44. if (it.contentEquals(playerTwoWinningStreak))
  45. return WIN_VALUE
  46. }
  47. }
  48.  
  49. this.mapIndexed { index, row -> row[index] }.toCharArray().also {
  50. if (it.contentEquals(playerOneWinningStreak))
  51. return LOSE_VALUE
  52. if (it.contentEquals(playerTwoWinningStreak))
  53. return WIN_VALUE
  54. }
  55. this.mapIndexed { index, row -> row[SIZE - 1 - index] }.toCharArray().also {
  56. if (it.contentEquals(playerOneWinningStreak))
  57. return LOSE_VALUE
  58. if (it.contentEquals(playerTwoWinningStreak))
  59. return WIN_VALUE
  60. }
  61.  
  62. return NO_WINNER
  63. }
  64.  
  65. private fun move(index: Int): Boolean {
  66. if (index in 1..9) {
  67. val col = (index - 1) % SIZE
  68. val row = SIZE - 1 - (index - 1) / SIZE
  69.  
  70. if (board[row][col] == EMPTY_SPOT) {
  71. board[row][col] = PLAYER_ONE_SYMBOL
  72. return true
  73. }
  74. return false
  75. } else {
  76. return false
  77. }
  78. }
  79.  
  80. private fun minimax(board: Matrix, depth: Int, isMax: Boolean, alpha: Int, beta: Int): Int {
  81. val score = board.evaluateState()
  82. var alpha = alpha
  83. var beta = beta
  84.  
  85. steps++
  86.  
  87. if (score == WIN_VALUE)
  88. return score - depth
  89. if (score == LOSE_VALUE)
  90. return score + depth
  91. if (!isMoveLeft())
  92. return NO_WINNER
  93.  
  94. if (isMax) {
  95. var best = Int.MIN_VALUE
  96. for (row in 0 until SIZE) {
  97. for (col in 0 until SIZE) {
  98. if (board[row][col] == EMPTY_SPOT) {
  99. board[row][col] = PLAYER_TWO_SYMBOL
  100.  
  101. best = max(best, minimax(board.clone(), depth + 1, !isMax, alpha, beta))
  102. alpha = max(best, alpha)
  103.  
  104. board[row][col] = EMPTY_SPOT
  105.  
  106. if (beta <= alpha)
  107. return best
  108. }
  109. }
  110. }
  111. return best
  112. } else {
  113. var best = Int.MAX_VALUE
  114. for (row in 0 until SIZE) {
  115. for (col in 0 until SIZE) {
  116. if (board[row][col] == EMPTY_SPOT) {
  117. board[row][col] = PLAYER_ONE_SYMBOL
  118. best = min(best, minimax(board.clone(), depth + 1, !isMax, alpha, beta))
  119. beta = min(best, beta)
  120. board[row][col] = EMPTY_SPOT
  121.  
  122. if (beta <= alpha)
  123. return best
  124. }
  125. }
  126. }
  127. return best
  128. }
  129. }
  130.  
  131. var steps = 0
  132.  
  133. private fun bestMove(board: Matrix): Point {
  134. var bestVal = Int.MIN_VALUE
  135. var bestMove = Point(-1, -1)
  136.  
  137. for (row in 0 until SIZE) {
  138. for (col in 0 until SIZE) {
  139. if (board[row][col] == EMPTY_SPOT) {
  140. board[row][col] = PLAYER_TWO_SYMBOL
  141.  
  142. val moveVal = minimax(board.clone(), 0, false, Int.MIN_VALUE, Int.MAX_VALUE)
  143. board[row][col] = EMPTY_SPOT
  144.  
  145. if (moveVal > bestVal) {
  146. bestVal = moveVal
  147. bestMove = Point(row, col)
  148. }
  149. }
  150. }
  151. }
  152.  
  153. return bestMove
  154. }
  155.  
  156. fun play() {
  157. while (true) {
  158.  
  159. while (!move(Scanner(System.`in`).nextInt())) {
  160. println("Invalid move")
  161. }
  162. print()
  163. if (board.evaluateState() != NO_WINNER) {
  164. println("You win!")
  165. println(steps)
  166. break
  167. } else if (!isMoveLeft()) {
  168. println("Draw")
  169. println(steps)
  170. break
  171. }
  172.  
  173. val pcMove = bestMove(board)
  174. board[pcMove.first][pcMove.second] = PLAYER_TWO_SYMBOL
  175. print()
  176. if (board.evaluateState() != NO_WINNER) {
  177. println("You lose!")
  178. println(steps)
  179. break
  180. } else if (!isMoveLeft()) {
  181. println("Draw")
  182. println(steps)
  183. break
  184. }
  185. }
  186. }
  187.  
  188. fun print() {
  189. println(
  190. " " + Arrays.deepToString(board)
  191. .replace(",", " ")
  192. .replace("[", "")
  193. .replace("]", "\n")
  194. )
  195. }
  196. }
  197.  
  198. fun main() {
  199. val board = TicTacToeGame()
  200. board.print()
  201. board.play()
  202. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement