Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

L8 #420

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
15 changes: 15 additions & 0 deletions AIPlayer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class AIPlayer(private val id: Int, private val game: Kalaha) extends Player(id) {

private val logicEngine = LogicEngine(game, id)

override def getId: Int = id

override def makeMove(time: Int): Int = {

logicEngine.makeMove(time: Int)

}

override def getEnemyMove(move: Int): Unit = logicEngine.updateEnemyMove(move)

}
105 changes: 105 additions & 0 deletions Kalaha.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import scala.util.control.Breaks.break

class Kalaha(private val field1: Array[Int], private val field2: Array[Int]) {

def this() = {

this(Array(6,6,6,6,6,6,0),Array(6,6,6,6,6,6,0))

}

def move(id: Int, field: Int): Int ={

var level = id == 1
var tmpField = nextField(level)
var points = tmpField(field)
tmpField(field) = 0
var index = field
while(points > 0 && index <= 6){
index += 1
if index == 7 then {
index = 0
level = !level
tmpField = nextField(level)
}
tmpField(index) += 1
points -= 1
}

if (id == 1) == level && index <= 5 then
val otherField = nextField(!level)
if tmpField(index) == 1 then
tmpField(6) += otherField(5 - index)
otherField(5-index) = 0

if index == 6 then
if (id == 1) == level then
if level then 1 else 2
else
if level then 1 else 2
else
if id == 1 then 2 else 1
}

def getScore(id: Int): Int =
if id == 1 then field1(6) - field2(6)
else field2(6) - field1(6)

def isOver():Boolean = {

var isOver1 = true
var isOver2 = true
var i = 0
while(i < 6){
if field1(i) != 0 then isOver1 = false
i += 1
}
i = 0
while(i < 6){
if field2(i) != 0 then isOver2 = false
i += 1
}
isOver1 || isOver2
}

def whoWon():Int = {

var res = 0
val res1 = field1.foldLeft(0)((x, sum) => sum + x)
val res2 = field2.foldLeft(0)((x, sum) => sum + x)
if res1 > res2 then res = 1
else if res1 < res2 then res = 2
res
}

def printFields(id: Int): Unit = {

var playerField = field1
var enemyField = field2.reverse

if id == 2 then
playerField = field2
enemyField = field1.reverse

println("|---------------Enemy Field---------------|")
println("|Base |--6--|--5--|--4--|--3--|--2--|--1--|")
enemyField.foreach(x => printf("|%5d",x))
println("|")
println("|-----------------------------------------|")
playerField.foreach(x => printf("|%5d",x))
println("|")
println("|--1--|--2--|--3--|--4--|--5--|--6--| Base|")
println("|--------------Player Field---------------|")
}

def copy(): Kalaha = new Kalaha(field1.clone(), field2.clone())

def getField(id: Int): Array[Int] =
if id == 1 then field1
else field2

//val nextField1: Int => Array[Int] = id => if id == 1 then field1 else field2

val nextField: Boolean => Array[Int] = value =>if value then field1 else field2

}
105 changes: 105 additions & 0 deletions LogicEngine.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import scala.annotation.tailrec
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.*
import scala.concurrent.ExecutionContext.Implicits.global

class LogicEngine(val game: Kalaha, val playerId: Int) {

var moves: List[Int] = List[Int]()
val decisions = new MyTree(6, game)
var bestMove: Int = 0

def updateEnemyMove(move: Int): Unit = moves = moves :+ move

def makeMove(time: Int): Int = {
val start = System.currentTimeMillis()
if decisions.getRoot.getValue._3 == 0 then
if moves.isEmpty then decisions.getRoot.setValue(decisions.getRoot.getValue._1, decisions.getRoot.getValue._2, playerId)
else {
decisions.getRoot.setValue(game.getScore(playerId), game, playerId)
moves = List()
}
var root = decisions.getRoot
moves.foreach(move =>{
if !root.hasKids then {
fillChildren()
root = root.getKids(move)
}
else root = root.getKids(move)

})
moves = List()
simulate(time*1000, start)
decisions.setRoot(decisions.getRoot.getKids(bestMove))
bestMove
}

def fillChildren(): Unit ={
@tailrec
def fillKid(curr: Node, restOfMoves: List[Int]):Unit =
restOfMoves match {
case List() => ()
case h::t =>
simulateIteration(h, curr, curr.getValue._3)
fillKid(curr.getKids(h),t)
}


}

def updateBestMove(): Unit =
var choiceMove = (0,0)
var bestScore = -100
var i = 0
decisions.getRoot.bestChoice(playerId).foreach((res, next) =>{
if game.getField(playerId)(i) != 0 then {
if res > bestScore then
bestScore = res
choiceMove = (i, next)
else if choiceMove._2 != playerId && res == bestScore && next == playerId then
bestScore = res
choiceMove = (i, next)
}
i += 1
})
bestMove = choiceMove._1

def simulate(time: Int, start: Long): Unit =

def simulateMove(curr: Node): Unit =
if (System.currentTimeMillis() - start) < (time* 3 / 4) then {
if curr.hasKids then
curr.getKids.foreach(kid =>{
simulateMove(kid)
})
else
val f1 = Future(simulateIteration(0,curr, curr.getValue._3))
val f2 = Future(simulateIteration(1,curr, curr.getValue._3))
val f3 = Future(simulateIteration(2,curr, curr.getValue._3))
val f4 = Future(simulateIteration(3,curr, curr.getValue._3))
val f5 = Future(simulateIteration(4,curr, curr.getValue._3))
val f6 = Future(simulateIteration(5,curr, curr.getValue._3))
if ((System.currentTimeMillis() - start) < (time * 4 / 5)) {
Await.result(f1, Duration.Inf)
Await.result(f2, Duration.Inf)
Await.result(f3, Duration.Inf)
Await.result(f4, Duration.Inf)
Await.result(f5, Duration.Inf)
Await.result(f6, Duration.Inf)
}
else ()
}
while((System.currentTimeMillis() - start) < (time* 4 / 5)){
simulateMove(decisions.getRoot)
decisions.getRoot.countSubtree()
updateBestMove()
}

def simulateIteration(fieldNumber: Int, curr: Node, currPlayerId: Int): Unit = {
val simulationGame = curr.getValue._2.copy()
val whoseNext = simulationGame.move(currPlayerId, fieldNumber)
curr.addNewKidAt((simulationGame.getScore(playerId), simulationGame, whoseNext), fieldNumber)
}

def showTree(): Unit = decisions.print()
}
9 changes: 9 additions & 0 deletions Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
object Main {
def main(args: Array[String]): Unit = {

val menu = new Menu()
menu.run()


}
}
54 changes: 54 additions & 0 deletions Menu.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import scala.io.StdIn.*

class Menu() {

val time = 30

def run(): Unit =
val game = new Kalaha()
println("KALAHA")
println("1.Singleplayer")
println("2.Multiplayer")
println("3.Simulation")
println("4.Exit")
print("Choice: ")

var choice = readInt()

if choice == 1 then
choice = difficulty(game)
if choice == 2 then
val p1 = new Player(1)
val p2 = new Player(2)
val server = new Server(p1, p2, game, time)
choice = server.play()
if choice == 3 then
val p1 = new AIPlayer(1, game)
val p2 = new AIPlayer(2, game)
val server = new Server(p1, p2, game, time)
choice = server.play()
if choice != 4 then run()

def difficulty(game: Kalaha): Int =
println("Select difficulty level:")
println("1.Easy")
println("2.Hard")
print("Choice: ")

var choice = readInt()

if choice == 1 then
val p1 = new Player(1)
val p2 = new RandomPlayer(2, game)
val server = new Server(p1, p2, game, time)
println("You are Player 1")
choice = server.play()
if choice == 2 then
val p1 = new Player(1)
val p2 = new AIPlayer(2, game)
val server = new Server(p1, p2, game, time)
println("You are Player 1")
choice = server.play()

choice
}
15 changes: 15 additions & 0 deletions Player.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import scala.io.StdIn.*

class Player(private val id: Int) {

def makeMove(time: Int): Int ={

print("\nSelect field number: ")
val field = readInt()
field - 1
}

def getId: Int = id

def getEnemyMove(move: Int): Unit = ()
}
22 changes: 22 additions & 0 deletions RandomPlayer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import scala.io.StdIn.readInt
import scala.util.Random

class RandomPlayer(private val id: Int, private val game: Kalaha) extends Player(id) {

override def makeMove(time: Int): Int ={

var isOk = false
var choice = 0
while(!isOk){

choice = Random.nextInt(6)
if game.getField(id)(choice) != 0 then isOk = true

}
choice
}

override def getId: Int = id

override def getEnemyMove(move: Int): Unit = ()
}
48 changes: 48 additions & 0 deletions Server.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import scala.util.Random
import scala.concurrent.{Await, Future}
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import java.util.concurrent.TimeUnit

class Server(private val player1: Player,private val player2: Player,private val game: Kalaha,private val time: Int):

def play(): Int =

var movingPlayer:Player = player1
var next = 1
val rng = Random.nextInt()
if rng % 2 == 1 then movingPlayer = player2
next = 2

while(!game.isOver() ){
println("Player "+ movingPlayer.getId + " moving")
game.printFields(movingPlayer.getId)
try{
val FutureChoice = Future(movingPlayer.makeMove(time))
val choice = Await.result(FutureChoice,Duration(time, TimeUnit.SECONDS))

if choice < 0 || choice > 5 then
println(choice + " is a wrong move! You loose your turn")
if next == 1 then next = 2
else next = 1
else
if next == 1 then player2.getEnemyMove(choice)
else player1.getEnemyMove(choice)
next = game.move(movingPlayer.getId, choice)
println("Field " + (choice + 1) + " chosen")
}
catch{
case e:java.util.concurrent.TimeoutException => println("Czas minal!")
return 4

}
if next == 1 then movingPlayer = player1
else movingPlayer = player2

}
game.printFields(movingPlayer.getId)
val winner = game.whoWon()
println("GAME IS OVER!")
if winner == 0 then println("It is a draw!!!\nCONGRATULATION")
else println("\nand the winner is...\nPlayer " + winner + "!!!")
0
Loading