Repository: setokinto/slack-shogi

Issue:
将棋盤モジュールを作る
将棋盤モジュールを作る

- 入力と入力とそれに対するエラーのインターフェースを作る
- 盤面を表示する
- 将棋盤の盤面を入力に従って管理する

Discussion:

Patch:
diff --git a/app/modules/shogi.py b/app/modules/shogi.py
index 4c2b930..3373116 100644
--- a/app/modules/shogi.py
+++ b/app/modules/shogi.py
@@ -51,9 +51,11 @@ class Koma(Enum):
         if self.value & 0x10:
             return False
         return True
-
-class ShogiCantMoveException(Exception):
-    pass
+    def promote(self):
+        try:
+            return Koma(self.value | 0x10)
+        except ValueError:
+            return self
 
 class Shogi:
     # TODO: implement komaochi
@@ -61,6 +63,8 @@ class Shogi:
         self.first = True
         self.first_tegoma = []
         self.second_tegoma = []
+        self.last_move_x = None
+        self.last_move_y = None
         self.board = [
             [
                 Koma.opponent_kyosha,
@@ -163,20 +167,21 @@ class Shogi:
             ],
         ]
     def move(self, from_x, from_y, to_x, to_y, promote):
-        """
-            if from_x and from_y is -1, the koma is from komadai
-        """
         koma = self.board[from_y][from_x]
-        # TODO: check for movable
-        if False: # not movable:
-            raise ShogiCantMoveException()
         koma_for_komadai = self.board[to_y][to_x]
         if koma_for_komadai is not Koma.empty:
-            # TODO: move to komadai
-            pass
+            if self.first:
+                self.first_tegoma.append(koma_for_komadai)
+            else:
+                self.second_tegoma.append(koma_for_komadai)
         self.board[from_y][from_x] = Koma.empty
-        self.board[to_y][to_x] = koma # TODO: in case promote is true
+        if promote:
+            self.board[to_y][to_x] = koma.promote()
+        else:
+            self.board[to_y][to_x] = koma
         self.first = not self.first
+        self.last_move_x = to_x
+        self.last_move_y = to_y
 
     def movable(self, from_x, from_y, to_x, to_y, promote):
         board = self.board
@@ -213,6 +218,48 @@ class Shogi:
                         return True
         return False
 
+    def drop(self, koma, to_x, to_y):
+        if self.first:
+            self.first_tegoma.remove(koma)
+        else:
+            self.second_tegoma.remove(koma)
+        koma_for_komadai = self.board[to_y][to_x]
+        self.board[to_y][to_x] = koma
+        if koma_for_komadai is not Koma.empty:
+            if self.first:
+                self.first_tegoma.append(koma_for_komadai)
+            else:
+                self.second_tegoma.append(koma_for_komadai)
+        self.first = not self.first
+        self.last_move_x = to_x
+        self.last_move_y = to_y
+
+    def droppable(self, koma, to_x, to_y):
+        if self.first:
+            tegoma = self.first_tegoma
+        else:
+            tegoma = self.second_tegoma
+        if koma in tegoma and self.board[to_y][to_x] is Koma.empty:
+            if koma is Koma.fu or koma is Koma.opponent_fu:
+                for y_board in self.board:
+                    if y_board[to_x] is koma:
+                        # 2fu
+                        return False
+            if koma is Koma.fu or koma is Koma.kyosha:
+                if to_y == 0:
+                    return False
+            if koma is Koma.keima:
+                if to_y <= 1:
+                    return False
+            if koma is Koma.opponent_fu or koma is Koma.opponent_kyosha:
+                if to_y == 8:
+                    return False
+            if koma is Koma.opponent_keima:
+                if to_y >= 7:
+                    return False
+            return True
+        return False
+
     def checkObstacle(self, from_x, from_y, to_x, to_y):
         if self.board[from_y][from_x].is_keima():
             return True


Test patch:
diff --git a/test/modules/shogi_test.py b/test/modules/shogi_test.py
index 9538c50..d768dde 100644
--- a/test/modules/shogi_test.py
+++ b/test/modules/shogi_test.py
@@ -145,10 +145,6 @@ class ShogiTest(unittest.TestCase):
         movable = shogi.movable(3, 6, 2, 8, True)
         self.assertTrue(movable)
 
-
-
-        
-
         shogi.first = True
         # 81 kyo narazu
         movable = shogi.movable(1, 1, 1, 0, False)
@@ -234,6 +230,107 @@ class ShogiTest(unittest.TestCase):
         movable = shogi.movable(5, 8, 5, 7, True)
         self.assertFalse(movable)
 
+    def test_drop(self):
+        shogi = Shogi()
+        shogi.first_tegoma = [Koma.kin]
+        shogi.second_tegoma = [Koma.opponent_kin]
+        shogi.drop(Koma.kin, 4, 4)
+        self.assertEqual(shogi.board[4][4], Koma.kin)
+        shogi.drop(Koma.opponent_kin, 3, 3)
+        self.assertEqual(shogi.board[3][3], Koma.opponent_kin)
+
+    def test_droppable(self):
+        shogi = Shogi()
+        shogi.first_tegoma = [Koma.kin]
+        shogi.second_tegoma = [Koma.opponent_kin]
+
+        shogi.first = True
+        # have
+        droppable = shogi.droppable(Koma.kin, 4, 4)
+        self.assertTrue(droppable)
+        # opponent
+        droppable = shogi.droppable(Koma.opponent_kin, 4, 4)
+        self.assertFalse(droppable)
+        # not have
+        droppable = shogi.droppable(Koma.gin, 4, 4)
+        self.assertFalse(droppable)
+
+        shogi.first = False
+        droppable = shogi.droppable(Koma.opponent_kin, 4, 4)
+        self.assertTrue(droppable)
+        # opponent
+        droppable = shogi.droppable(Koma.kin, 4, 4)
+        self.assertFalse(droppable)
+        # not have
+        droppable = shogi.droppable(Koma.opponent_gin, 4, 4)
+        self.assertFalse(droppable)
+
+    def test_droppable_nifu(self):
+        shogi = Shogi()
+        shogi.first_tegoma = [Koma.fu]
+        shogi.second_tegoma = [Koma.opponent_fu]
+
+        shogi.first = True
+        droppable = shogi.droppable(Koma.fu, 4, 4)
+        self.assertFalse(droppable)
+        shogi.first = False
+        droppable = shogi.droppable(Koma.opponent_fu, 4, 4)
+        self.assertFalse(droppable)
+
+    def test_droppable_fu_kyo_kei(self):
+        shogi = Shogi()
+        shogi.board[0][0] = Koma.empty
+        shogi.board[2][0] = Koma.empty
+        shogi.board[6][0] = Koma.empty
+        shogi.board[8][0] = Koma.empty
+        shogi.first_tegoma = [Koma.fu, Koma.kyosha, Koma.keima]
+        shogi.second_tegoma = [Koma.opponent_fu, Koma.opponent_kyosha, Koma.opponent_keima]
+        shogi.first = True
+        # keima
+        droppable = shogi.droppable(Koma.keima, 0, 1)
+        self.assertFalse(droppable)
+        droppable = shogi.droppable(Koma.keima, 0, 2)
+        self.assertTrue(droppable)
+        droppable = shogi.droppable(Koma.opponent_keima, 1, 2)
+        self.assertFalse(droppable)
+        droppable = shogi.droppable(Koma.keima, 0, 3)
+        self.assertTrue(droppable)
+        # fu
+        droppable = shogi.droppable(Koma.fu, 0, 0)
+        self.assertFalse(droppable)
+        droppable = shogi.droppable(Koma.fu, 0, 1)
+        self.assertTrue(droppable)
+        # kyo
+        droppable = shogi.droppable(Koma.kyosha, 0, 0)
+        self.assertFalse(droppable)
+        droppable = shogi.droppable(Koma.kyosha, 0, 1)
+        self.assertTrue(droppable)
+
+        shogi.first = False
+        # keima
+        droppable = shogi.droppable(Koma.opponent_keima, 0, 7)
+        self.assertFalse(droppable)
+        droppable = shogi.droppable(Koma.opponent_keima, 0, 6)
+        self.assertTrue(droppable)
+        droppable = shogi.droppable(Koma.keima, 1, 6)
+        self.assertFalse(droppable)
+        droppable = shogi.droppable(Koma.opponent_keima, 0, 5)
+        self.assertTrue(droppable)
+        # fu
+        droppable = shogi.droppable(Koma.opponent_fu, 0, 7)
+        self.assertTrue(droppable)
+        droppable = shogi.droppable(Koma.opponent_fu, 0, 8)
+        self.assertFalse(droppable)
+        droppable = shogi.droppable(Koma.opponent_fu, 0, 0)
+        self.assertTrue(droppable)
+        droppable = shogi.droppable(Koma.opponent_fu, 0, 1)
+        self.assertTrue(droppable)
+        # kyosha
+        droppable = shogi.droppable(Koma.opponent_kyosha, 0, 7)
+        self.assertTrue(droppable)
+        droppable = shogi.droppable(Koma.opponent_kyosha, 0, 8)
+        self.assertFalse(droppable)
+
 
     def test_find_koma(self):
         shogi = Shogi()
@@ -247,4 +344,14 @@ class ShogiTest(unittest.TestCase):
 
         koma_positions = shogi.find_koma(Koma.hisha)
         self.assertIn([7, 7], koma_positions)
+    
+    def test_last_move(self):
+        shogi = Shogi()
+        shogi.second_tegoma = [Koma.opponent_fu]
+        shogi.move(0, 6, 0, 5, False)
+        self.assertEqual(shogi.last_move_x, 0)
+        self.assertEqual(shogi.last_move_y, 5)
+        shogi.drop(Koma.opponent_fu, 5, 5)
+        self.assertEqual(shogi.last_move_x, 5)
+        self.assertEqual(shogi.last_move_y, 5)