Optimization
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
"""Contains function to iterate different kinds of possible actions"""
|
"""Contains function to iterate different kinds of possible actions"""
|
||||||
from typing import Iterator, List
|
from typing import Iterator, List, Tuple
|
||||||
from . import board
|
from . import board
|
||||||
from . import board_actions
|
from . import board_actions
|
||||||
|
|
||||||
@@ -168,29 +168,33 @@ def possible_field_move_actions(
|
|||||||
"""Enumerate all possible move actions
|
"""Enumerate all possible move actions
|
||||||
from one field stack to another field stack"""
|
from one field stack to another field stack"""
|
||||||
first_empty_field_id = -1
|
first_empty_field_id = -1
|
||||||
my_id = search_board.state_identifier
|
cardstacks = [(index, stack)
|
||||||
for index, stack in enumerate(_get_cardstacks(search_board)):
|
for index, stack in enumerate(_get_cardstacks(search_board))]
|
||||||
if not stack:
|
cardstacks = [x for x in cardstacks if x[1]]
|
||||||
continue
|
cardstacks = sorted(cardstacks, key=lambda x: len(x[1]))
|
||||||
# TODO: sort all substacks by length
|
substacks: List[Tuple[int, List[board.Card]]] = []
|
||||||
for substack in (stack[i:] for i in range(len(stack))):
|
|
||||||
|
for index, stack in cardstacks:
|
||||||
|
substacks.extend((index, substack)
|
||||||
|
for substack in (stack[i:]
|
||||||
|
for i in range(len(stack))))
|
||||||
|
|
||||||
|
for index, substack in substacks:
|
||||||
for other_index, other_stack in enumerate(search_board.field):
|
for other_index, other_stack in enumerate(search_board.field):
|
||||||
if index == other_index:
|
if index == other_index:
|
||||||
continue
|
continue
|
||||||
if other_stack:
|
if other_stack:
|
||||||
if not _can_stack(other_stack[-1], substack[0]):
|
if not _can_stack(other_stack[-1], substack[0]):
|
||||||
continue
|
continue
|
||||||
|
elif len(substack) == len(search_board.field[index]):
|
||||||
|
continue
|
||||||
elif first_empty_field_id == -1:
|
elif first_empty_field_id == -1:
|
||||||
first_empty_field_id = other_index
|
first_empty_field_id = other_index
|
||||||
elif other_index != first_empty_field_id:
|
elif other_index != first_empty_field_id:
|
||||||
continue
|
continue
|
||||||
elif len(substack) == len(search_board.field[index]):
|
|
||||||
continue
|
|
||||||
assert search_board.state_identifier == my_id
|
|
||||||
yield board_actions.MoveAction(
|
yield board_actions.MoveAction(
|
||||||
cards=substack, source_id=index, destination_id=other_index
|
cards=substack, source_id=index, destination_id=other_index
|
||||||
)
|
)
|
||||||
assert search_board.state_identifier == my_id
|
|
||||||
|
|
||||||
|
|
||||||
def possible_actions(
|
def possible_actions(
|
||||||
|
|||||||
@@ -54,30 +54,31 @@ class SolitaireSolver:
|
|||||||
self.stack = ActionStack()
|
self.stack = ActionStack()
|
||||||
self.stack.push(self.search_board)
|
self.stack.push(self.search_board)
|
||||||
|
|
||||||
def solve(self) -> List[board_actions.Action]:
|
def solve(self) -> Iterator[List[board_actions.Action]]:
|
||||||
max_goal = 0
|
|
||||||
action = None
|
|
||||||
while self.stack:
|
while self.stack:
|
||||||
|
|
||||||
assert (self.search_board.state_identifier ==
|
assert (self.search_board.state_identifier ==
|
||||||
self.stack.state_stack[-1])
|
self.stack.state_stack[-1])
|
||||||
action = self.stack.get()
|
action = self.stack.get()
|
||||||
|
|
||||||
if not action:
|
if not action:
|
||||||
self.stack.pop()
|
self.stack.pop()
|
||||||
self.stack.action_stack[-1].undo(self.search_board)
|
self.stack.action_stack[-1].undo(self.search_board)
|
||||||
assert (self.search_board.state_identifier
|
assert (self.search_board.state_identifier
|
||||||
in self.state_set)
|
in self.state_set)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
action.apply(self.search_board)
|
action.apply(self.search_board)
|
||||||
|
|
||||||
if self.search_board.solved():
|
if self.search_board.solved():
|
||||||
return self.stack.action_stack
|
yield self.stack.action_stack
|
||||||
|
|
||||||
if self.search_board.state_identifier in self.state_set:
|
if self.search_board.state_identifier in self.state_set:
|
||||||
action.undo(self.search_board)
|
action.undo(self.search_board)
|
||||||
assert self.search_board.state_identifier in self.state_set
|
assert self.search_board.state_identifier in self.state_set
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.state_set.add(self.search_board.state_identifier)
|
self.state_set.add(self.search_board.state_identifier)
|
||||||
self.stack.push(self.search_board)
|
self.stack.push(self.search_board)
|
||||||
if sum(self.search_board.goal.values()) > max_goal:
|
|
||||||
max_goal = sum(self.search_board.goal.values())
|
|
||||||
print(self.search_board.goal)
|
|
||||||
|
|
||||||
return self.stack.action_stack
|
return self.stack.action_stack
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from .context import shenzhen_solitaire
|
from .context import shenzhen_solitaire
|
||||||
from shenzhen_solitaire.board import NumberCard, SpecialCard, Board
|
from shenzhen_solitaire.board import NumberCard, SpecialCard, Board, Position
|
||||||
|
from shenzhen_solitaire.board_actions import MoveAction, BunkerizeAction, GoalAction, HuaKillAction
|
||||||
from shenzhen_solitaire import board_possibilities
|
from shenzhen_solitaire import board_possibilities
|
||||||
from .boards import my_board
|
from .boards import my_board
|
||||||
|
|
||||||
@@ -15,52 +16,57 @@ class ChainTestClass(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertTrue(my_board.check_correct())
|
self.assertTrue(my_board.check_correct())
|
||||||
sequence = [
|
sequence = [
|
||||||
0,
|
MoveAction(
|
||||||
4,
|
cards=[
|
||||||
0,
|
NumberCard(
|
||||||
1,
|
suit=NumberCard.Suit.Red,
|
||||||
0,
|
number=7),
|
||||||
0,
|
NumberCard(
|
||||||
8,
|
suit=NumberCard.Suit.Green,
|
||||||
0,
|
number=6)],
|
||||||
1,
|
source_id=3,
|
||||||
3,
|
destination_id=7),
|
||||||
0,
|
BunkerizeAction(
|
||||||
9,
|
card=NumberCard(
|
||||||
0,
|
suit=NumberCard.Suit.Red,
|
||||||
2,
|
number=6),
|
||||||
0,
|
bunker_id=0,
|
||||||
1,
|
field_id=2,
|
||||||
1,
|
to_bunker=True),
|
||||||
1,
|
GoalAction(
|
||||||
2,
|
card=NumberCard(
|
||||||
0,
|
suit=NumberCard.Suit.Green,
|
||||||
2,
|
number=1),
|
||||||
1,
|
source_id=2,
|
||||||
6,
|
source_position=Position.Field),
|
||||||
12,
|
MoveAction(
|
||||||
0,
|
cards=[
|
||||||
0,
|
NumberCard(
|
||||||
1,
|
suit=NumberCard.Suit.Red,
|
||||||
0,
|
number=4)],
|
||||||
0,
|
source_id=2,
|
||||||
17,
|
destination_id=5),
|
||||||
11,
|
GoalAction(
|
||||||
1,
|
card=NumberCard(
|
||||||
0,
|
suit=NumberCard.Suit.Red,
|
||||||
0,
|
number=1),
|
||||||
0,
|
source_id=2,
|
||||||
0,
|
source_position=Position.Field),
|
||||||
0,
|
HuaKillAction(source_field_id=2),
|
||||||
0,
|
MoveAction(
|
||||||
0,
|
cards=[
|
||||||
0,
|
NumberCard(
|
||||||
0,
|
suit=NumberCard.Suit.Black, number=9),
|
||||||
0,
|
NumberCard(suit=NumberCard.Suit.Red, number=8)],
|
||||||
0,
|
source_id=6,
|
||||||
0,
|
destination_id=2),
|
||||||
0,
|
GoalAction(
|
||||||
0]
|
card=NumberCard(
|
||||||
for action_index in sequence:
|
suit=NumberCard.Suit.Green, number=2),
|
||||||
|
source_id=6,
|
||||||
|
source_position=Position.Field)
|
||||||
|
]
|
||||||
|
for action in sequence:
|
||||||
step = list(board_possibilities.possible_actions(my_board))
|
step = list(board_possibilities.possible_actions(my_board))
|
||||||
step[action_index].apply(my_board)
|
self.assertIn(action, step)
|
||||||
|
action.apply(my_board)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from .boards import my_board
|
|||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
A = solver.SolitaireSolver(my_board)
|
A = solver.SolitaireSolver(my_board)
|
||||||
B = A.solve()
|
for _, B in zip(range(1), A.solve()):
|
||||||
print(*B, sep='\n')
|
print(*B, sep='\n')
|
||||||
print(len(B))
|
print(len(B))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user