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 #441

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Default ignored files
KalahaGame/out/
12 changes: 12 additions & 0 deletions KalahaGame/KalahaGame.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="scala-sdk-3.0.2 (2)" level="application" />
</component>
</module>
Binary file added KalahaGame/akka-actor_2.13-2.6.18.jar
Binary file not shown.
Binary file added KalahaGame/config-1.4.0.jar
Binary file not shown.
Binary file added KalahaGame/scala-java8-compat_2.13-1.0.0.jar
Binary file not shown.
Binary file added KalahaGame/scala-library-2.13.7.jar
Binary file not shown.
3 changes: 3 additions & 0 deletions KalahaGame/src/application.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
akka{
log-dead-letters = off
}
129 changes: 129 additions & 0 deletions KalahaGame/src/game/Board.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package game

class Board(){
var player1houses = Array(6, 6, 6, 6, 6, 6, 0)
var player2houses = Array(6, 6, 6, 6, 6, 6, 0)
val baseIndex = 6

def setForTest(p1ar: Array[Int], p2ar: Array[Int]): Unit = {
player1houses = p1ar
player2houses = p2ar
}

def move(player: Int, house: Int): Boolean = {
var playerHouses = Array[Int]()
var opponentHouses = Array[Int]()

player match{
case 1 =>
playerHouses = player1houses
opponentHouses = player2houses
case 2 =>
playerHouses = player2houses
opponentHouses = player1houses
case _ =>
}
var nextMove = false

if(house < 1 || house > 6) then
throw new IllegalArgumentException("House number must be between 1 and 6")
else{
val houseIndex = house - 1
if playerHouses(houseIndex) == 0 then
throw new IllegalArgumentException("Cannot take seeds from an empty house")
else{
var seeds = playerHouses(houseIndex)
playerHouses(houseIndex) = 0
var currentHouse = houseIndex + 1
while(seeds > 0) {
while (currentHouse < 7 && seeds > 0) {
if(seeds == 1 && currentHouse < 6 && playerHouses(currentHouse) == 0) then {
playerHouses(baseIndex) += opponentHouses(getOppositeHouseIndex(currentHouse)) + 1
opponentHouses(getOppositeHouseIndex(currentHouse)) = 0
seeds -= 1
} else{
playerHouses(currentHouse) += 1
seeds -= 1
currentHouse += 1
}
}
if seeds == 0 && currentHouse == 7 then
nextMove = true
else {
currentHouse = 0
while (currentHouse < 6 && seeds > 0) {
opponentHouses(currentHouse) += 1
seeds -= 1
currentHouse += 1
}
currentHouse = 0

}
}
nextMove
}
}

}
def getOppositeHouseIndex(myHouseIndex: Int): Int = {
5 - myHouseIndex
}

def isFinished(): Boolean = {
var sum1 = 0
var sum2 = 0

for(i <- 0 to 5){
sum1 += player1houses(i)
sum2 += player2houses(i)
}
// println(sum1)
// println(sum2)
sum1 == 0 || sum2 == 0
}

def getFinalScore(): (Int, Int) ={
var p1score = 0
var p2score = 0

for(i <- 0 to 6){
p1score += player1houses(i)
p2score += player2houses(i)
}

(p1score, p2score)
}

def copyBoard(): Board ={
val copy = new Board()
copy.player1houses = player1houses.clone()
copy.player2houses = player2houses.clone()
copy

}

def printBoard(): Unit ={
println(" Player 2 ")
println(" 6 5 4 3 2 1")
println("------------------------------------------------")
var counter = player2houses.size - 2
print(" ")
while(counter >= 0){
print(" ( " + player2houses(counter) + " ) ")
counter -= 1
}
println()
counter = 0
println("( "+player2houses(baseIndex)+" )" + " " +"( "+ player1houses(baseIndex)+" )" )
print(" ")
while(counter < player1houses.size - 1){
print(" ( " + player1houses(counter) + " ) ")
counter += 1
}
println()
println("------------------------------------------------")
println(" 1 2 3 4 5 6")
println(" Player 1 ")
}

}
159 changes: 159 additions & 0 deletions KalahaGame/src/game/GameServer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package game

import akka.actor.{Actor, ActorRef, Kill, PoisonPill, Props, actorRef2Scala}
import akka.pattern.*
import akka.util.Timeout
import game.Board
import game.GameServer.{MoveChoice, NextMove, StartGame}
import KalahaGame.system
import players.*
import Player.{MoveRequest, GameOver}

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
import scala.io.StdIn.readInt
import scala.util.{Failure, Random, Success}



class GameServer(player1Mode: Int, player2Mode: Int) extends Actor{
val board = new Board()
var currentPlayer = 1
var nextMove = false
implicit private val timeout: Timeout = Timeout(30.seconds)
val player1 = {
if player1Mode == 1 then system.actorOf(Props(HumanPlayer(1)), "player1")
else system.actorOf(Props(Computer(1, board)), "player1")
}

val player2 = {
if player2Mode == 1 then system.actorOf(Props(HumanPlayer(2)), "player2")
else system.actorOf(Props(Computer(2, board)), "player2")
}

def receive = {
case StartGame =>
printGameBoard()
requestMove()
case NextMove => requestMove()
}

def requestMove(): Unit ={
printTurnMessage()
val f = getCurrentPlayer() ? MoveRequest
f.onComplete{
case Success(MoveChoice(pNum, choice)) =>
if checkIfPossible(pNum, choice) then
makeMove(pNum, choice)
else
println("This move is not possible")
requestMove()

case Failure(ex) =>
printEndMessage()
changeCurrentPlayer()
walkoverForPlayer(currentPlayer)
}
}

def makeMove(playerNum: Int, house: Int): Unit ={
printPlayersChoiceMessage(house)
Thread.sleep(100)
nextMove = board.move(playerNum, house)
if gameFinished() then
printGameBoard()
printEndMessage()
printFinalScore()
endGame()
else
if nextMove then {
printNextMoveMessage()
printGameBoard()
}else{
changeCurrentPlayer()
printGameBoard()
}
self ! NextMove
}

def getRandomMove(playerNum: Int): Int = {
val rand = new Random()
var choice = rand.nextInt(5) + 1
while(!checkIfPossible(playerNum, choice)){
choice = rand.nextInt(5) + 1
}
choice
}

def checkIfPossible(playerNum: Int, house: Int): Boolean ={
playerNum match{
case 1 => board.player1houses(house - 1) > 0
case 2 => board.player2houses(house - 1) > 0
}
}

def printTurnMessage(): Unit ={
println(s"Player $currentPlayer your turn")
}
def printNextMoveMessage(): Unit ={
println(s"Player $currentPlayer has next move")
}
def printPlayersChoiceMessage(choice: Int): Unit ={
println(s"Player $currentPlayer choice: $choice")
}

def getCurrentPlayer(): ActorRef ={
if currentPlayer == 1 then player1
else player2
}

def changeCurrentPlayer(): Unit ={
if currentPlayer == 1 then currentPlayer = 2
else currentPlayer = 1
}

def printGameBoard(): Unit = {
board.printBoard()
}

def gameFinished(): Boolean = {
board.isFinished()
}

def printEndMessage(): Unit ={
println("\n-------------------GAME OVER--------------------\n")
}


def endGame(): Unit ={
player1 ! GameOver
player2 ! GameOver
self ! PoisonPill
context.system.terminate()
System.exit(0)
}

def printFinalScore(): Unit ={
val (s1, s2): (Int, Int) = board.getFinalScore()
println(" Final score ")
println(s" Player 1: $s1 Player 2: $s2 ")
if s1 > s2 then
println(" Player 1 is the winner!")
else if s2 > s1 then
println(" Player 2 is the winner!")
else println("It's a draw!")
println()
}

def walkoverForPlayer(playerNum: Int): Unit ={
println(" Walkover!")
println(s" Player $playerNum wins!\n")
endGame()
}
}

object GameServer{
case class MoveChoice(val playerNum: Int, val choice: Int)
case class StartGame()
case class NextMove()
}
63 changes: 63 additions & 0 deletions KalahaGame/src/game/KalahaGame.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package game

import akka.actor.{ActorSystem, Props}
import GameServer.StartGame

import scala.io.StdIn.{readInt, readLine}

object KalahaGame extends App {

val system = ActorSystem("ServerSystem")
var p1choice = -1
var p2choice = -1

println("Welcome to Kalaha Game! \n")

println("Instructions:\n\n" +
"The Kalaha board has 6 small pits, called houses, on each side and a big pit, called store, at each end. \n" +
"The object of the game is to capture more seeds than your opponent.\n" +
"Start of the game:" +
"1. At the beginning of the game, six seeds are placed in each house.\n" +
"2. Each player controls the six houses and their seeds on the player's side of the board.\n" +
"3. The player's score is the number of seeds in the store to their right.\n" +
"4. Players take turns sowing their seeds. On a turn, the player removes all seeds from one of the houses under their control.\n" +
"Moving counter-clockwise, the player drops one seed in each house in turn, including the player's own store but not their opponent's.\n" +
"To choose their moves players have maximum of 30 seconds, after which the game will be terminated\n" +
"5. If the last sown seed lands in an empty house owned by the player, and the opposite house contains seeds,\n" +
"both the last seed and the opposite seeds are captured and placed into the player's store.\n" +
"6. If the last sown seed lands in the player's store, the player gets an additional move.\n" +
"End of game:\n" +
"If one of the players runs out of the time, the game finishes with WALKOVER.\n" +
"When one player no longer has any seeds in any of their houses, the game ends.\n" +
"The other player moves all remaining seeds to their store, and the player with the most seeds in their store wins.\n")

println("Are you ready? Press ENTER\n")
readLine()

println("Choose your players' modes: \n")

while (p1choice != 1 && p1choice != 2) {
println("Choose Player 1: ")
println("1 - Human player 2 - Bot player")
try {
p1choice = readInt()
} catch {
case e => println("Invalid input, must be a number")
}
}
while (p2choice != 1 && p2choice != 2) {
println("Choose Player 2: ")
println("1 - Human player 2 - Bot player")
try {
p2choice = readInt()
} catch {
case e => println("Invalid input, must be a number")
}
}

val server = system.actorOf(Props(new GameServer(p1choice, p2choice)))

println("The game is beginning!\n")

server ! StartGame
}
Loading