main_testing4/shogun.scala
changeset 493 244df77507c2
parent 476 7550c816187a
equal deleted inserted replaced
492:4ffba2f72692 493:244df77507c2
     1 // Main Part 4 about the Shogun Board Game
     1 // Resit about the Shogun Board Game
     2 //=========================================
     2 //====================================
       
     3 
       
     4 // Task 1 - 6 see below
     3 
     5 
     4 object M4 {   
     6 object M4 {   
     5 
     7 
     6 type Pos = (Int, Int)    // a position on a chessboard 
     8 type Pos = (Int, Int)    // a position on a chessboard 
     7 
     9 
    15 abstract class Piece {
    17 abstract class Piece {
    16   def pos : Pos       
    18   def pos : Pos       
    17   def col : Colour    
    19   def col : Colour    
    18   def en : Int      // energy for Pawns 1 - 4, for Kings 1 - 2
    20   def en : Int      // energy for Pawns 1 - 4, for Kings 1 - 2
    19 }
    21 }
    20 
       
    21 case class Pawn(en: Int, col: Colour, pos: Pos) extends Piece
    22 case class Pawn(en: Int, col: Colour, pos: Pos) extends Piece
    22 case class King(en: Int, col: Colour, pos: Pos) extends Piece
    23 case class King(en: Int, col: Colour, pos: Pos) extends Piece
    23 
    24 
       
    25 // how to extract components from pieces
    24 //val p = Pawn(4, Wht, (3,2))
    26 //val p = Pawn(4, Wht, (3,2))
    25 //assert(p.pos == (3,2))
    27 //assert(p.pos == (3,2))
    26 //assert(p.col == Wht)
    28 //assert(p.col == Wht)
    27 //assert(p.en == 4)  
    29 //assert(p.en == 4)  
    28 
    30 
    87 
    89 
    88 // pretty printing a board
    90 // pretty printing a board
    89 def print_board(b: Board): Unit = {
    91 def print_board(b: Board): Unit = {
    90   println()
    92   println()
    91   for (i <- 8 to 1 by -1) {
    93   for (i <- 8 to 1 by -1) {
    92     println("+" ++ "-" * 31 ++ "+")
    94     println("----" * 8)
    93     for (j <- 1 to 8) {
    95     for (j <- 1 to 8) {
    94       val opc = occupied((j,i), b)
    96       val opc = occupied((j,i), b)
    95       if (opc.isDefined) print(s"|${pp(opc.get)}") 
    97       if (opc.isDefined) print(s"|${pp(opc.get)}") 
    96       else print("|   ")
    98       else print("|   ")
    97     }
    99     }
    98     println("|")
   100     println("|")
    99   } 
   101   } 
   100   println("+" ++ "-" * 31 ++ "+")
   102   println("----" * 8)
   101 }
   103 }
   102 
   104 
   103 // example board: initial board
   105 // example board: initial board
   104 val b_init = Board(Set(King(2,Wht,(4,1)), King(1,Red,(5,8)),
   106 val b_init = Board(Set(King(2,Wht,(4,1)), King(1,Red,(5,8)),
   105                   		 Pawn(4,Wht,(1,1)), Pawn(4,Red,(1,8)),
   107                   		 Pawn(4,Wht,(1,1)), Pawn(4,Red,(1,8)),
   127 // |   |   |   |   |   |   |   |   |
   129 // |   |   |   |   |   |   |   |   |
   128 // --------------------------------
   130 // --------------------------------
   129 // |PW4|PW3|PW2|KW2|PW1|PW4|PW3|PW2|
   131 // |PW4|PW3|PW2|KW2|PW1|PW4|PW3|PW2|
   130 // --------------------------------
   132 // --------------------------------
   131 
   133 
   132 
       
   133 // Moves
   134 // Moves
   134 //=======
   135 //=======
   135 abstract class Move
   136 abstract class Move
   136 case object U extends Move    // up
   137 case object U extends Move    // up
   137 case object D extends Move    // down
   138 case object D extends Move    // down
   138 case object R extends Move    // right
   139 case object R extends Move    // right
   139 case object L extends Move    // left
   140 case object L extends Move    // left
   140 case object RU extends Move   // ...
   141 case object RU extends Move   // first right, then possibly up
   141 case object LU extends Move
   142 case object LU extends Move   // first left, then possibly up
   142 case object RD extends Move
   143 case object RD extends Move   // ...
   143 case object LD extends Move
   144 case object LD extends Move
   144 case object UR extends Move
   145 case object UR extends Move
   145 case object UL extends Move
   146 case object UL extends Move
   146 case object DR extends Move
   147 case object DR extends Move
   147 case object DL extends Move
   148 case object DL extends Move
   148 
   149 
   149 // Task 1: calculates all next possible positions according to a move
   150 //======================
       
   151 // ADD YOUR CODE BELOW
       
   152 //======================
       
   153 
       
   154 
       
   155 // Task 1: 
   150 def eval(pc: Piece, m: Move, en: Int, b: Board) : Set[Piece] = {
   156 def eval(pc: Piece, m: Move, en: Int, b: Board) : Set[Piece] = {
   151   val p = pc.pos
   157   val pos = pc.pos
   152   val c = pc.col
   158   if (!inside(pos, b)) then Set()
   153   if (!inside(p, b)) Set() 
   159   else if (en == 0) then 
   154   else if (en == 0 && !is_occupied(p, b)) Set(pc)
   160     if is_occupied(pos, b) then   
   155   else if (en == 0 && is_occupied(p, b) && c != occupied_by(p, b).get) Set(pc)
   161       val occupant = occupied_by(pos, b)
   156   else if (is_occupied(p, b)) Set()  
   162       if occupant.get != pc.col then
   157   else m match {
   163         Set(pc) 
   158     case  U => eval(incy(pc), U, en - 1, b) 
   164       else Set()
   159     case  D => eval(decy(pc), D, en - 1, b) 
   165     else Set(pc)
   160     case  R => eval(incx(pc), R, en - 1, b) 
   166   else if (is_occupied(pos,b)) then Set()
   161     case  L => eval(decx(pc), L, en - 1, b) 
   167   else {m match {
   162     case  RU => eval(incx(pc), RU, en - 1, b) ++ eval(pc, U, en, b)
   168     case U => eval(incy(pc), U, en-1, b)
   163     case  LU => eval(decx(pc), LU, en - 1, b) ++ eval(pc, U, en, b)
   169     case D => eval(decy(pc), D, en-1, b)
   164     case  RD => eval(incx(pc), RD, en - 1, b) ++ eval(pc, D, en, b)
   170     case R => eval(incx(pc), R, en-1, b)
   165     case  LD => eval(decx(pc), LD, en - 1, b) ++ eval(pc, D, en, b)
   171     case L => eval(decx(pc), L, en-1, b)
   166     case  UR => eval(incy(pc), UR, en - 1, b) ++ eval(pc, R, en, b)
   172     case RU => eval(incx(pc), RU, en-1, b) ++ eval(pc, U, en, b)
   167     case  UL => eval(incy(pc), UL, en - 1, b) ++ eval(pc, L, en, b)
   173     case LU => eval(decx(pc), LU, en-1, b) ++ eval(pc, U, en, b)
   168     case  DR => eval(decy(pc), DR, en - 1, b) ++ eval(pc, R, en, b)
   174     case RD => eval(incx(pc), RD, en-1, b) ++ eval(pc, D, en, b)
   169     case  DL => eval(decy(pc), DL, en - 1, b) ++ eval(pc, L, en, b)
   175     case LD => eval(decx(pc), LD, en-1, b) ++ eval(pc, D, en, b)
   170 }}
   176     case UR => eval(incy(pc), UR, en-1, b) ++ eval(pc, R, en, b)
       
   177     case UL => eval(incy(pc), UL, en-1, b) ++ eval(pc, L, en, b)
       
   178     case DR => eval(decy(pc), DR, en-1, b) ++ eval(pc, R, en, b)
       
   179     case DL => eval(decy(pc), DL, en-1, b) ++ eval(pc, L, en, b) 
       
   180   }
       
   181   }
       
   182 }
       
   183 
       
   184 
       
   185 // Task 2: 
       
   186 def all_moves(pc: Piece, b: Board) : Set[Piece] = {
       
   187   val temporary_board = b - pc //not sure if this is
       
   188   //what was meant by changes to the board (Perth discussion on keats)
       
   189   val all_possible_moves = Set(U, D, R, L, RU, LU, RD, LD, UR, UL, DR, DL)
       
   190   all_possible_moves.flatMap(move => eval(pc, move, pc.en, temporary_board))
       
   191 } 
       
   192 
       
   193 
       
   194 // Task 3: 
       
   195 def attacked(c: Colour, b: Board) : Set[Piece] = {
       
   196   val my_pieces = b.pces.filter(_.col == c)
       
   197   val opponent_pieces = b.pces.filter(_.col != c)
       
   198   val attacked_pieces = opponent_pieces.filter(pc => my_pieces.flatMap(p => all_moves(p, b)).exists(_.pos == pc.pos))
       
   199   attacked_pieces
       
   200 }
       
   201 
       
   202 
       
   203 // Task 4: 
       
   204 def attackedN(pc: Piece, b: Board) : Int = {
       
   205   val opponent_pieces = b.pces.filter(_.col != pc.col)
       
   206   val attacking_pieces_num = opponent_pieces.count(p => all_moves(p, b).exists(_.pos == pc.pos))
       
   207   attacking_pieces_num
       
   208 }
       
   209 
       
   210 
       
   211 // Task 5: 
       
   212 def protectedN(pc: Piece, b: Board) : Int = {
       
   213   val temporary_board = b - pc 
       
   214   val my_pieces = b.pces.filter(_.col == pc.col)
       
   215   val protecting_pieces_num = my_pieces.count(p => all_moves(p, temporary_board).exists(_.pos == pc.pos))
       
   216   protecting_pieces_num
       
   217 }
       
   218 
       
   219 
       
   220 // Task 6: 
       
   221 def legal_moves(pc: Piece, b: Board) : Set[Piece] = {
       
   222   if is_king(pc) then 
       
   223     val all_king_moves = all_moves(pc, b)
       
   224     val valid_king_moves = all_king_moves.filter{m =>
       
   225       val temporary_board = Board(b.pces.filter(_.pos != m.pos))//remove potentially captured pieces
       
   226       val updated_temp_board = temporary_board + m
       
   227       val opponent_pieces = updated_temp_board.pces.filter(_.col != pc.col)
       
   228       val opponent_moves = opponent_pieces.flatMap(p => all_moves(p, updated_temp_board))
       
   229       !(opponent_moves.exists(_.pos == m.pos))}
       
   230     valid_king_moves
       
   231   else {all_moves(pc, b)}
       
   232 }
   171 
   233 
   172 /*
   234 /*
   173 // test cases
   235 // more test cases
   174 val pw_a = Pawn(4, Wht, (4,4))
   236 //=================
   175 println(eval(pw_a, U,  4, b_init))  // Set(Pawn(4,Wht,(4,8)))
       
   176 println(eval(pw_a, U,  3, b_init))  // Set(Pawn(4,Wht,(4,7)))
       
   177 println(eval(pw_a, RU, 4, b_init))  // Set(Pawn(4,Wht,(6,6)), Pawn(4,Wht,(4,8)),
       
   178                                     //     Pawn(4,Wht,(5,7)), Pawn(4,Wht,(7,5)), 
       
   179                                     //     Pawn(4,Wht,(8,4)))
       
   180 val pw_b = Pawn(4, Red, (4,4))
       
   181 println(eval(pw_b, RU, 4, b_init))  // Set(Pawn(4,Red,(8,4)), Pawn(4,Red,(7,5)), 
       
   182                                            Pawn(4,Red,(6,6)), Pawn(4,Red,(5,7)))
       
   183 */
       
   184 
       
   185 
       
   186 // Task 2: calculates all possible moves for a piece
       
   187 def all_moves(pc: Piece, b: Board) : Set[Piece] = {
       
   188   Set(U,D,L,R,RU,LU,RD,LD,UR,UL,DR,DL).flatMap(eval(pc, _, pc.en, b - pc))
       
   189 }
       
   190 
       
   191 /*
       
   192 // test cases
       
   193 val pw_c = Pawn(2, Wht, (4,4))
       
   194 val pw_d = Pawn(3, Red, (4,4))
       
   195 println(all_moves(pw_c, b_init))  
       
   196   // Set(Pawn(2,Wht,(3,5)), Pawn(2,Wht,(2,4)), Pawn(2,Wht,(3,3)), Pawn(2,Wht,(5,5)), 
       
   197   //     Pawn(2,Wht,(6,4)), Pawn(2,Wht,(4,6)), Pawn(2,Wht,(4,2)), Pawn(2,Wht,(5,3)))
       
   198 println(all_moves(pw_d, b_init)) 
       
   199   // Set(Pawn(3,Red,(4,7)), Pawn(3,Red,(5,2)), Pawn(3,Red,(3,2)), Pawn(3,Red,(1,4)), 
       
   200   //     Pawn(3,Red,(6,3)), Pawn(3,Red,(3,6)), Pawn(3,Red,(2,5)), Pawn(3,Red,(2,3)), 
       
   201   //     Pawn(3,Red,(4,1)), Pawn(3,Red,(5,6)), Pawn(3,Red,(7,4)), Pawn(3,Red,(6,5)))
       
   202 */
       
   203 
       
   204 
       
   205 // Task 3: calculates all pieces that are attacked by colour
       
   206 def attacked(c: Colour, b: Board) : Set[Piece] = {
       
   207   val (me, opponent) = b.pces.partition(_.col == c)
       
   208   val all = me.flatMap(all_moves(_, b))
       
   209   opponent.filter(pc => is_occupied(pc.pos, Board(all)))
       
   210 }
       
   211 
       
   212 // test cases
       
   213 val b_checkmate = Board(Set(King(2, Red, (4,2)), King(2, Wht, (7,1)),
       
   214                             Pawn(3, Red, (6,1)), Pawn(2, Wht, (8,4)),
       
   215                             Pawn(4, Red, (4,4)), Pawn(2, Wht, (4,1)),
       
   216                             Pawn(4, Red, (5,3)), Pawn(3, Wht, (8,7)),
       
   217                             Pawn(3, Red, (6,5))))
       
   218 print_board(b_checkmate)
       
   219 println(attacked(Red, b_checkmate)) // Set(Pawn(2,Wht,(8,4)), King(2,Wht,(7,1)))
       
   220 println(attacked(Wht, b_checkmate)) // Set(Pawn(3,Red,(6,1)))
       
   221 println(attacked(Wht, b_init)) // Set()
       
   222 println(attacked(Red, b_init)) // Set()
       
   223 
       
   224 // Task 4: calculates the number of pieces that attack a piece
       
   225 def attackedN(pc: Piece, b: Board) : Int = {
       
   226   val (me, opponent) = b.pces.partition(_.col == pc.col)
       
   227   val all = opponent.toList.flatMap(all_moves(_, b))
       
   228   all.count(_.pos == pc.pos)
       
   229 }
       
   230 
       
   231 // test cases
       
   232 println(attackedN(Pawn(2, Wht, (8,4)), b_checkmate)) // 3
       
   233 println(attackedN(King(2, Wht, (7,1)), b_checkmate)) // 1
       
   234 println(attackedN(Pawn(3, Red, (6,1)), b_checkmate)) // 1
       
   235 
       
   236 
       
   237 // Task 5: calculates the number of pieces that protect a piece
       
   238 def protectedN(pc: Piece, b: Board) : Int = {
       
   239   val (me, opponent) = b.pces.partition(_.col == pc.col)
       
   240   val all = (me - pc).toList.flatMap(all_moves(_, (b - pc)))
       
   241   all.count(_.pos == pc.pos)
       
   242 }
       
   243 
       
   244 println(protectedN(Pawn(2, Wht, (8,4)), b_checkmate)) // 1
       
   245 println(protectedN(Pawn(4, Red, (5,3)), b_checkmate)) // 3
       
   246 
       
   247 
       
   248 
       
   249 //
       
   250 val pw1 = Pawn(4, Wht, (4,6))
   237 val pw1 = Pawn(4, Wht, (4,6))
   251 val pw2 = Pawn(4, Wht, (2,4))
   238 val pw2 = Pawn(4, Wht, (2,4))
   252 val pw3 = Pawn(3, Red, (6,8))
   239 val pw3 = Pawn(3, Red, (6,8))
   253 val pw4 = Pawn(2, Red, (2,8))
   240 val pw4 = Pawn(2, Red, (2,8))
   254 val bt = b_init + pw1 + pw2
   241 val bt = b_init + pw1 + pw2
   255 
   242 
   256 print_board(bt)
   243 print_board(bt)
   257 println(s"Capture Red: ${attacked(Wht, bt)}")
   244 println(s"Capture Red: ${attacked(Wht, bt)}")
   258   // Set(Pawn(2,Red,(2,8)), Pawn(3,Red,(6,8)))
   245   // => Set(Pawn(2,Red,(2,8)), Pawn(3,Red,(6,8)))
       
   246 
   259 println(s"Capture Wht: ${attacked(Red, bt)}")
   247 println(s"Capture Wht: ${attacked(Red, bt)}")
   260   // Set(Pawn(4,Wht,(4,6)))
   248   // => Set(Pawn(4,Wht,(4,6)))
       
   249 
   261 println(s"ProtectedN:  ${protectedN(pw3, bt)}")
   250 println(s"ProtectedN:  ${protectedN(pw3, bt)}")
   262   // 2
   251   // => 2
       
   252 
   263 println(s"AttackedN:   ${attackedN(pw4, bt)}")
   253 println(s"AttackedN:   ${attackedN(pw4, bt)}")
   264   // 2
   254   // => 2
       
   255 
   265 println(s"all moves:   ${all_moves(pw2, bt)}")
   256 println(s"all moves:   ${all_moves(pw2, bt)}")
   266   // Set(Pawn(4,Wht,(4,2)), Pawn(4,Wht,(1,7)), Pawn(4,Wht,(5,3)), Pawn(4,Wht,(5,5)), 
   257   // => Set(Pawn(4,Wht,(4,2)), Pawn(4,Wht,(1,7)), Pawn(4,Wht,(5,3)), Pawn(4,Wht,(5,5)), 
   267   //     Pawn(4,Wht,(2,8)), Pawn(4,Wht,(3,7)), Pawn(4,Wht,(6,4)))
   258   //        Pawn(4,Wht,(2,8)), Pawn(4,Wht,(3,7)), Pawn(4,Wht,(6,4)))
   268 
   259 */
   269 }
   260 
   270 
   261 }
   271 
   262 
       
   263