branch: elpa/aidermacs
commit 846f283f83999556a7eee59dcc71736db605d3fb
Author: Kang Tu <tni...@gmail.com>
Commit: GitHub <nore...@github.com>

    doc: Add hard mode for battleship game using o3-mini high model (#70)
    
    * feat: Add aider-implement-todo function to implement TODOs in current 
context
    
    * feat: Add `aider-implement-todo` function description to README
    
    * docs(readme): update aider command description
    
    * feat: Add HardComputerPlayer class with probability density strategy
    
    feat: Implement hard mode for computer player using probability density 
strategy
    
    feat: Add computer_vs_hard method and corresponding unit test
    
    feat: Enhance probability grid with ship size weighting and adjacent bonuses
    
    feat: Add normal_first option to computer_vs_hard in battleship game
    
    feat: enhance HardComputerPlayer AI with hunt-target modes and probability 
optimization
    
    test: Add simulation to compare normal vs hard AI win rates
    
    feat: enhance HardComputerPlayer AI with adaptive learning and improved 
targeting
    
    feat: add quantum-inspired algorithms and advanced tactics to 
HardComputerPlayer
    
    refactor(game): simplify hard computer player with probability density 
strategy
    
    * chore: Translate Chinese comments to English in battleship examples
    
    chore: Replace Chinese comments with English in ComputerPlayer class
    
    * refactor: move decodeLoc method from HardComputerPlayer to HumanPlayer
    
    * feat(keybindings): add implement requirement menu option
    
    * docs(readme): clarify aider-implement-todo behavior and scope
    
    * docs(readme): update installation dependency formatting
    
    * docs: clarify package-vc-install as emacs built-in
    
    * docs: add emphasis to `aider-implement-todo` in README
    
    ---------
    
    Co-authored-by: Kang Tu <kang...@apple.com>
---
 README.org                       |  10 ++--
 aider-doom.el                    |   1 +
 aider.el                         |   2 +-
 examples/battleship/fleet.py     |   2 +-
 examples/battleship/game.py      | 114 ++++++++++++++++++++++++++++++++++-----
 examples/battleship/test_game.py |  29 +++++++++-
 6 files changed, 138 insertions(+), 20 deletions(-)

diff --git a/README.org b/README.org
index 9544b60b1a..80b1c1d885 100644
--- a/README.org
+++ b/README.org
@@ -43,8 +43,8 @@ When being called with the universal argument (`C-u`), a 
prompt will offer the u
 
 *** Write code:
   - (`aider-function-or-region-refactor`): If a region is selected, ask Aider 
to refactor the selected region. Otherwise, ask Aider to change / refactor the 
function under the cursor.
-  - (`aider-implement-todo`): Implement TODO comments in current context.
-    - If cursor is on a comment line, implement that specific comment.
+  - *(`aider-implement-todo`): Implement requirement in comments in-place, in 
current context.*
+    - If cursor is on a comment line, implement that specific comment in-place.
     - If cursor is inside a function, implement TODOs for that function.
     - Otherwise implement TODOs for the entire current file.
 
@@ -66,8 +66,7 @@ You can add your own Elisp functions to support your specific 
use cases. Feel fr
 
 ** Vanilla Emacs Installation
 - [[https://aider.chat/docs/install.html][Install aider]]
-- Install the dependency [[https://github.com/magit/transient][Transient]] 
using your package manager.
-- Install the dependency [[https://github.com/magit/magit][Magit]] using your 
package manager.
+- Install the emacs dependency library 
[[https://github.com/magit/transient][Transient]], and 
[[https://github.com/magit/magit][Magit]] using your package manager.
 - Install aider.el with the following code:
 
 *** With 
[[https://github.com/radian-software/straight.el?tab=readme-ov-file][Straight]]
@@ -91,7 +90,8 @@ If you have Straight installed
     ;; Optional: Set a key binding for the transient menu
     (global-set-key (kbd "C-c a") 'aider-transient-menu))
 #+END_SRC
-*** With 
[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Fetching-Package-Sources.html#:~:text=One%20way%20to%20do%20this,just%20like%20any%20other%20package.][package-vc-install]]
+
+*** With 
[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Fetching-Package-Sources.html#:~:text=One%20way%20to%20do%20this,just%20like%20any%20other%20package.][package-vc-install]]
 (emacs built-in)
 Install Aider.el by running the following code within Emacs
 #+BEGIN_SRC emacs-lisp
 (package-vc-install '(aider :url "https://github.com/tninja/aider.el";))
diff --git a/aider-doom.el b/aider-doom.el
index 35a1a0c205..be8db18fc3 100644
--- a/aider-doom.el
+++ b/aider-doom.el
@@ -37,6 +37,7 @@
                     :desc "Architecture" "d" #'aider-architect-discussion
                     :desc "Change" "c" #'aider-code-change
                     :desc "Refactor Function or Region" "r" 
#'aider-function-or-region-refactor
+                    :desc "Implement Requirement in-place" "i" 
#'aider-implement-todo
                     :desc "Undo change" "u" #'aider-undo-last-change
                     :desc "Show last commit" "g" #'aider-magit-show-last-commit
                     )
diff --git a/aider.el b/aider.el
index 066e84ab75..0654ed9e50 100644
--- a/aider.el
+++ b/aider.el
@@ -140,7 +140,7 @@ Affects the system message too.")
     ("r" "Refactor Function or Region" aider-function-or-region-refactor)
     ("U" "Write Unit Test" aider-write-unit-test)
     ("T" "Fix Failing Test Under Cursor" aider-fix-failing-test-under-cursor)
-    ("i" "Implement TODOs" aider-implement-todo)
+    ("i" "Implement Requirement in-place" aider-implement-todo)
     ("m" "Show Last Commit with Magit" aider-magit-show-last-commit)
     ("u" "Undo Last Change" aider-undo-last-change)
     ]
diff --git a/examples/battleship/fleet.py b/examples/battleship/fleet.py
index eb5d4f1a03..ff1c044c04 100644
--- a/examples/battleship/fleet.py
+++ b/examples/battleship/fleet.py
@@ -57,5 +57,5 @@ class FleetGroup:
     def show(self):
         for fleet in self.fleets:
             fleet.show()
-            print()  # 添加一个空行以分隔不同的舰队
+            print()  # add an empty line to separate fleets
 
diff --git a/examples/battleship/game.py b/examples/battleship/game.py
index f8d0151f8d..d6e3164498 100644
--- a/examples/battleship/game.py
+++ b/examples/battleship/game.py
@@ -170,19 +170,19 @@ class ComputerPlayer(Player):
         board_size = self.board_size
         hit_history = self.hit_history
         
-        # 获取未击沉的船只大小列表
+        # get sizes of unsunk ships
         remaining_sizes = []
         for fleet in player.fleet_group.fleets:
             if not fleet.is_sunk():
                 remaining_sizes.append(fleet.size)
         
-        # 找出所有连续命中但未击沉的点
+        # get all consecutive hit points that are not sunk
         hits_in_progress = []
         hits_only = [(x, y) for x, y, hit in hit_history if hit]
         
-        # 分析连续命中点的方向
+        # Analyze the orientation of consecutive hit points
         for x, y in hits_only:
-            # 检查是否已经是已击沉的船只的一部分
+            # check if this hit is part of a sunk ship
             is_sunk = False
             for fleet in player.fleet_group.fleets:
                 if fleet.is_sunk() and (x, y) in fleet.coordinates:
@@ -192,38 +192,38 @@ class ComputerPlayer(Player):
                 hits_in_progress.append((x, y))
         
         if hits_in_progress:
-            # 如果有连续命中点,分析可能的方向
+            # If there are multiple consecutive hit points, analyze possible 
orientation
             if len(hits_in_progress) > 1:
-                # 确定方向
+                # Determine the orientation
                 points = sorted(hits_in_progress)
-                if points[0][0] == points[1][0]:  # 水平方向
+                if points[0][0] == points[1][0]:  # horizontal direction
                     direction = 'horizontal'
                     x = points[0][0]
                     possible_y = [points[0][1]-1, points[-1][1]+1]
                     candidates = [(x, y) for y in possible_y if 0 <= y < 
board_size[1]]
-                else:  # 垂直方向
+                else:  # vertical direction
                     direction = 'vertical'
                     y = points[0][1]
                     possible_x = [points[0][0]-1, points[-1][0]+1]
                     candidates = [(x, y) for x in possible_x if 0 <= x < 
board_size[0]]
             else:
-                # 单个命中点,尝试四个方向
+                # For a single hit point, try all four directions
                 x, y = hits_in_progress[0]
                 candidates = [(x-1,y), (x+1,y), (x,y-1), (x,y+1)]
                 candidates = [(x,y) for x,y in candidates 
                              if 0 <= x < board_size[0] and 0 <= y < 
board_size[1]]
             
-            # 过滤掉已经打击过的位置
+            # Filter out positions that have already been targeted
             candidates = [(x,y) for x,y in candidates 
                          if (x,y,True) not in hit_history and (x,y,False) not 
in hit_history]
             
             if candidates:
                 x, y = random.choice(candidates)
             else:
-                # 如果没有合适的相邻点,随机选择
+                # If no valid adjacent cell is available, choose randomly
                 x, y = self._random_shot(board_size, hit_history)
         else:
-            # 没有进行中的命中,使用概率分布选择
+            # If there are no ongoing hit sequences, use a random shot
             x, y = self._random_shot(board_size, hit_history)
         
         hit_result = self.hit(player, x, y)
@@ -248,6 +248,82 @@ class ComputerPlayer(Player):
         return random.choice(possible_hits)
 
 
+class HardComputerPlayer(ComputerPlayer):
+    """
+    Hard mode: use probability density strategy for selecting the best move
+    """
+
+    def input_and_hit(self, player):
+        # Get board size and hit history
+        board_size = self.board_size
+        hit_history = self.hit_history
+
+        # get lengths of all opponent's unsunk ships
+        remaining_ships = [fleet.size for fleet in player.fleet_group.fleets 
if not fleet.is_sunk()]
+
+        # initialize probability grid with zeros
+        prob_grid = [[0] * board_size[1] for _ in range(board_size[0])]
+
+        # record shot coordinates; elements in hit_history are tuples (x, y, 
bool)
+        shot_cells = {(x, y): True for x, y, _ in hit_history}
+
+        # 对于每个剩余舰船的长度,尝试水平和垂直的放置,并累加概率分值
+        for size in remaining_ships:
+            for x in range(board_size[0]):
+                for y in range(board_size[1]):
+                    # horizontal placement: check if cells from (x, y) to (x, 
y+size-1) are within boundaries and not shot
+                    if y + size <= board_size[1]:
+                        if all((x, y + offset) not in shot_cells for offset in 
range(size)):
+                            for offset in range(size):
+                                prob_grid[x][y + offset] += size  # Increase 
weight based on ship size
+
+                    # vertical placement: check if cells from (x, y) to 
(x+size-1, y) are within boundaries and not shot
+                    if x + size <= board_size[0]:
+                        if all((x + offset, y) not in shot_cells for offset in 
range(size)):
+                            for offset in range(size):
+                                prob_grid[x + offset][y] += size  # Increase 
weight based on ship size
+
+        # Add bonus for cells adjacent to unsunk hit cells
+        bonus = 3  # Bonus weight for adjacent cell
+        for x, y, hit in hit_history:
+            if hit:  # cell was a hit
+                # Check if this hit cell belongs to an unsunk fleet
+                unsunk = False
+                for fleet in player.fleet_group.fleets:
+                    if (x, y) in fleet.coordinates and not fleet.is_sunk():
+                        unsunk = True
+                        break
+                if unsunk:
+                    for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
+                        nx, ny = x + dx, y + dy
+                        if 0 <= nx < board_size[0] and 0 <= ny < board_size[1] 
and (nx, ny) not in shot_cells:
+                            prob_grid[nx][ny] += bonus  # Boost adjacent cells 
near successful hit
+        max_prob = -1
+        candidates = []
+        for x in range(board_size[0]):
+            for y in range(board_size[1]):
+                if (x, y) not in shot_cells:
+                    cell_prob = prob_grid[x][y]
+                    if cell_prob > max_prob:
+                        max_prob = cell_prob
+                        candidates = [(x, y)]
+                    elif cell_prob == max_prob:
+                        candidates.append((x, y))
+
+        import random
+        if candidates:
+            x, y = random.choice(candidates)
+        else:
+            # 如果没有候选,退回到父类的随机策略
+            x, y = self._random_shot(board_size, hit_history)
+
+        hit_result = self.hit(player, x, y)
+        self.log_hit(x, y, hit_result)
+        print(f"{player.name}'s board: ")
+        player.show_myself()
+        print("=====================================")
+        return hit_result
+
 class Game:
 
     def __init__(self, fleet_names, board_size):
@@ -283,6 +359,20 @@ class Game:
         self.add_players(player1, player2)
         self.run()
 
+    def computer_vs_hard(self, normal_first=True):
+        """
+        # Start a game with ComputerPlayer vs HardComputerPlayer
+        """
+        player1 = ComputerPlayer("Normal CPU", self.board_size)
+        player2 = HardComputerPlayer("Hard CPU", self.board_size)
+        player1.random_init(self.fleet_names)
+        player2.random_init(self.fleet_names)
+        if normal_first:
+            self.add_players(player1, player2)
+        else:
+            self.add_players(player2, player1)
+        self.run()
+
 
 if __name__ == '__main__':
     game = Game(['carrier', 'battleship', 'cruiser', 'submarine', 'destroyer'
diff --git a/examples/battleship/test_game.py b/examples/battleship/test_game.py
index 6e46f9ec2b..bca9e1ae87 100644
--- a/examples/battleship/test_game.py
+++ b/examples/battleship/test_game.py
@@ -1,7 +1,7 @@
 
 import unittest
 
-from game import Player
+from game import Player, Game, ComputerPlayer, HardComputerPlayer
 
 
 class TestPlayer(unittest.TestCase):
@@ -13,3 +13,30 @@ class TestPlayer(unittest.TestCase):
         print()
         player.show_enemy()
         # player.fleet_group.show()
+
+    def test_computer_vs_hard(self):
+        """
+        # Unit test for battle between ComputerPlayer and HardComputerPlayer
+        """
+        fleet_names = ['carrier', 'battleship', 'cruiser', 'submarine', 
'destroyer']
+        board_size = (10, 10)
+        normal_wins = hard_wins = 0
+        for i in range(100):
+            game = Game(fleet_names, board_size)
+            if i % 2 == 0:
+                game.computer_vs_hard(normal_first=True)
+                if game.players[0].all_sunk():
+                    normal_wins += 1
+                if game.players[1].all_sunk():
+                    hard_wins += 1
+            else:
+                game.computer_vs_hard(normal_first=False)
+                if game.players[0].all_sunk():
+                    hard_wins += 1
+                if game.players[1].all_sunk():
+                    normal_wins += 1
+        print(f"Normal wins: {normal_wins}")
+        print(f"Hard wins: {hard_wins}")
+
+# Normal wins: 31
+# Hard wins: 69

Reply via email to