main_testing4/shogun.scala
changeset 476 7550c816187a
child 493 244df77507c2
equal deleted inserted replaced
475:59e005dcf163 476:7550c816187a
       
     1 // Main Part 4 about the Shogun Board Game
       
     2 //=========================================
       
     3 
       
     4 object M4 {   
       
     5 
       
     6 type Pos = (Int, Int)    // a position on a chessboard 
       
     7 
       
     8 // Colours: Red or White
       
     9 abstract class Colour
       
    10 case object Red extends Colour
       
    11 case object Wht extends Colour
       
    12 
       
    13 // Pieces: Either Pawns or Kings
       
    14 //===============================
       
    15 abstract class Piece {
       
    16   def pos : Pos       
       
    17   def col : Colour    
       
    18   def en : Int      // energy for Pawns 1 - 4, for Kings 1 - 2
       
    19 }
       
    20 
       
    21 case class Pawn(en: Int, col: Colour, pos: Pos) extends Piece
       
    22 case class King(en: Int, col: Colour, pos: Pos) extends Piece
       
    23 
       
    24 //val p = Pawn(4, Wht, (3,2))
       
    25 //assert(p.pos == (3,2))
       
    26 //assert(p.col == Wht)
       
    27 //assert(p.en == 4)  
       
    28 
       
    29 // checks if a piece is a king
       
    30 def is_king(pc: Piece) : Boolean = pc match {
       
    31   case King(_, _, _) => true
       
    32   case _ => false
       
    33 }
       
    34 
       
    35 // incrementing and decrementing the position of a piece
       
    36 def incx(pc: Piece) : Piece = pc match {
       
    37   case Pawn(en, c, (x,y)) => Pawn(en, c, (x+1,y))
       
    38   case King(en, c, (x,y)) => King(en, c, (x+1,y))
       
    39 }
       
    40 
       
    41 def incy(pc: Piece) : Piece = pc match {
       
    42   case Pawn(en, c, (x,y)) => Pawn(en, c, (x,y+1))
       
    43   case King(en, c, (x,y)) => King(en, c, (x,y+1))
       
    44 }
       
    45 
       
    46 def decx(pc: Piece) : Piece = pc match {
       
    47   case Pawn(en, c, (x,y)) => Pawn(en, c, (x-1,y))
       
    48   case King(en, c, (x,y)) => King(en, c, (x-1,y))
       
    49 }
       
    50 
       
    51 def decy(pc: Piece) : Piece = pc match {
       
    52   case Pawn(en, c, (x,y)) => Pawn(en, c, (x,y-1))
       
    53   case King(en, c, (x,y)) => King(en, c, (x,y-1))
       
    54 }
       
    55 
       
    56 //pretty printing colours and pieces
       
    57 def pp_color(c: Colour) : String = c match {
       
    58   case Red => "R"
       
    59   case Wht => "W"
       
    60 }
       
    61 
       
    62 def pp(pc: Piece) : String = pc match {
       
    63   case Pawn(n, c, _) => s"P${pp_color(c)}$n"
       
    64   case King(n, c, _) => s"K${pp_color(c)}$n"
       
    65 }
       
    66 
       
    67 // Boards are sets of pieces
       
    68 //===========================
       
    69 case class Board(pces: Set[Piece]) {
       
    70   def +(pc: Piece) : Board = Board(pces + pc)
       
    71   def -(pc: Piece) : Board = Board(pces - pc)
       
    72 }
       
    73 
       
    74 // checking whether a position is occupied in a board
       
    75 def occupied(p: Pos, b: Board) : Option[Piece] =  
       
    76   b.pces.find(p == _.pos)
       
    77   
       
    78 def occupied_by(p: Pos, b: Board) : Option[Colour] =
       
    79   occupied(p, b).map(_.col)
       
    80 
       
    81 def is_occupied(p: Pos, b: Board) : Boolean =
       
    82   occupied(p, b).isDefined
       
    83 
       
    84 // is a position inside a board
       
    85 def inside(p: Pos, b: Board): Boolean = 
       
    86   1 <= p._1 && 1 <= p._2 && p._1 <= 8 && p._2 <= 8 
       
    87 
       
    88 // pretty printing a board
       
    89 def print_board(b: Board): Unit = {
       
    90   println()
       
    91   for (i <- 8 to 1 by -1) {
       
    92     println("+" ++ "-" * 31 ++ "+")
       
    93     for (j <- 1 to 8) {
       
    94       val opc = occupied((j,i), b)
       
    95       if (opc.isDefined) print(s"|${pp(opc.get)}") 
       
    96       else print("|   ")
       
    97     }
       
    98     println("|")
       
    99   } 
       
   100   println("+" ++ "-" * 31 ++ "+")
       
   101 }
       
   102 
       
   103 // example board: initial board
       
   104 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)),
       
   106                   		 Pawn(3,Wht,(2,1)), Pawn(2,Red,(2,8)),
       
   107                   		 Pawn(2,Wht,(3,1)), Pawn(3,Red,(3,8)),
       
   108                   		 Pawn(1,Wht,(5,1)), Pawn(1,Red,(4,8)),
       
   109                   		 Pawn(4,Wht,(6,1)), Pawn(3,Red,(6,8)),
       
   110                   		 Pawn(3,Wht,(7,1)), Pawn(1,Red,(7,8)),
       
   111                   		 Pawn(2,Wht,(8,1)), Pawn(3,Red,(8,8))))
       
   112 
       
   113 //print_board(b_init)
       
   114 // --------------------------------
       
   115 // |PR4|PR2|PR3|PR1|KR1|PR3|PR1|PR3|
       
   116 // --------------------------------
       
   117 // |   |   |   |   |   |   |   |   |
       
   118 // --------------------------------
       
   119 // |   |   |   |   |   |   |   |   |
       
   120 // --------------------------------
       
   121 // |   |   |   |   |   |   |   |   |
       
   122 // --------------------------------
       
   123 // |   |   |   |   |   |   |   |   |
       
   124 // --------------------------------
       
   125 // |   |   |   |   |   |   |   |   |
       
   126 // --------------------------------
       
   127 // |   |   |   |   |   |   |   |   |
       
   128 // --------------------------------
       
   129 // |PW4|PW3|PW2|KW2|PW1|PW4|PW3|PW2|
       
   130 // --------------------------------
       
   131 
       
   132 
       
   133 // Moves
       
   134 //=======
       
   135 abstract class Move
       
   136 case object U extends Move    // up
       
   137 case object D extends Move    // down
       
   138 case object R extends Move    // right
       
   139 case object L extends Move    // left
       
   140 case object RU extends Move   // ...
       
   141 case object LU extends Move
       
   142 case object RD extends Move
       
   143 case object LD extends Move
       
   144 case object UR extends Move
       
   145 case object UL extends Move
       
   146 case object DR extends Move
       
   147 case object DL extends Move
       
   148 
       
   149 // Task 1: calculates all next possible positions according to a move
       
   150 def eval(pc: Piece, m: Move, en: Int, b: Board) : Set[Piece] = {
       
   151   val p = pc.pos
       
   152   val c = pc.col
       
   153   if (!inside(p, b)) Set() 
       
   154   else if (en == 0 && !is_occupied(p, b)) Set(pc)
       
   155   else if (en == 0 && is_occupied(p, b) && c != occupied_by(p, b).get) Set(pc)
       
   156   else if (is_occupied(p, b)) Set()  
       
   157   else m match {
       
   158     case  U => eval(incy(pc), U, en - 1, b) 
       
   159     case  D => eval(decy(pc), D, en - 1, b) 
       
   160     case  R => eval(incx(pc), R, en - 1, b) 
       
   161     case  L => eval(decx(pc), L, en - 1, b) 
       
   162     case  RU => eval(incx(pc), RU, en - 1, b) ++ eval(pc, U, en, b)
       
   163     case  LU => eval(decx(pc), LU, en - 1, b) ++ eval(pc, U, en, b)
       
   164     case  RD => eval(incx(pc), RD, en - 1, b) ++ eval(pc, D, en, b)
       
   165     case  LD => eval(decx(pc), LD, en - 1, b) ++ eval(pc, D, en, b)
       
   166     case  UR => eval(incy(pc), UR, en - 1, b) ++ eval(pc, R, en, b)
       
   167     case  UL => eval(incy(pc), UL, en - 1, b) ++ eval(pc, L, en, b)
       
   168     case  DR => eval(decy(pc), DR, en - 1, b) ++ eval(pc, R, en, b)
       
   169     case  DL => eval(decy(pc), DL, en - 1, b) ++ eval(pc, L, en, b)
       
   170 }}
       
   171 
       
   172 /*
       
   173 // test cases
       
   174 val pw_a = Pawn(4, Wht, (4,4))
       
   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))
       
   251 val pw2 = Pawn(4, Wht, (2,4))
       
   252 val pw3 = Pawn(3, Red, (6,8))
       
   253 val pw4 = Pawn(2, Red, (2,8))
       
   254 val bt = b_init + pw1 + pw2
       
   255 
       
   256 print_board(bt)
       
   257 println(s"Capture Red: ${attacked(Wht, bt)}")
       
   258   // Set(Pawn(2,Red,(2,8)), Pawn(3,Red,(6,8)))
       
   259 println(s"Capture Wht: ${attacked(Red, bt)}")
       
   260   // Set(Pawn(4,Wht,(4,6)))
       
   261 println(s"ProtectedN:  ${protectedN(pw3, bt)}")
       
   262   // 2
       
   263 println(s"AttackedN:   ${attackedN(pw4, bt)}")
       
   264   // 2
       
   265 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)), 
       
   267   //     Pawn(4,Wht,(2,8)), Pawn(4,Wht,(3,7)), Pawn(4,Wht,(6,4)))
       
   268 
       
   269 }
       
   270 
       
   271