package chess

import (
	"fmt"
	"strconv"
	"strings"
)

var pieceJPZ = []Piece{
	BR, BN, BS, BM, BK, BS, BN, BR,
	"", "", "", "", "", "", "", "",
	BP, BP, BP, BP, BP, BP, BP, BP,
	"", "", "", "", "", "", "", "",
	"", "", "", "", "", "", "", "",
	WP, WP, WP, WP, WP, WP, WP, WP,
	"", "", "", "", "", "", "", "",
	WR, WN, WS, WK, WM, WS, WN, WR,
}

const (
	MoveWK = 0
	MoveWM = 1
	MoveBM = 2
	MoveBK = 3
)

// RecordJPZ 走棋记录
type RecordJPZ struct {
	FromTo        [2]*PositionPiece
	CambodianMove [4]bool
}

// ChessJPZ 棋盘
type ChessJPZ struct {
	Variant int
	Width   int     // 宽度
	Height  int     // 高度
	Count   int     // 格子数量
	Act     bool    // 是否该白字走,false白棋
	Round   int     // 回合数
	Buf     []Piece // 棋子

	Castling      [4]bool // 王车易位可行性 [KQkq]
	EnPassant     int     // 过路兵位置
	CambodianMove [4]bool // 柬埔寨移动可行性(DEde，D白王，E白仕，d黑仕，e黑王)

	Records   []*RecordJPZ // 走棋记录
	Check     [2]bool      // 将军
	Checkmate [2]bool      // 将死
}

func (c *ChessJPZ) GetChess() []string {
	ret := make([]string, len(c.Buf))
	for k, v := range c.Buf {
		ret[k] = string(v)
	}
	return ret
}

func (c *ChessJPZ) GetAct() string {
	if c.Act {
		return "b"
	} else {
		return "w"
	}
}

func (c *ChessJPZ) GetCastling() []bool {
	ret := make([]bool, len(c.Castling))
	for k, v := range c.Castling {
		ret[k] = v
	}
	return ret
}

func (c *ChessJPZ) GetEnPassant() int {
	return c.EnPassant
}

func (c *ChessJPZ) GetCambodianMove() []bool {
	ret := make([]bool, len(c.CambodianMove))
	for k, v := range c.CambodianMove {
		ret[k] = v
	}
	return ret
}

func (c *ChessJPZ) GetRound() int {
	return c.Round
}

func (c *ChessJPZ) GetPiece(index int) Piece {
	return c.Buf[index]
}

func (c *ChessJPZ) GetCheck() []bool {
	ret := make([]bool, len(c.Check))
	for k, v := range c.Check {
		ret[k] = v
	}
	return ret
}

func (c *ChessJPZ) GetCheckmate() []bool {
	ret := make([]bool, len(c.Checkmate))
	for k, v := range c.Checkmate {
		ret[k] = v
	}
	return ret
}

func (c *ChessJPZ) NextAct() {
	// 判断将军
	c.Check[0] = c.IsCheck(true)
	c.Check[1] = c.IsCheck(false)
	// 判断将死
	c.Checkmate[0] = false
	c.Checkmate[1] = false
	if !c.Act && c.IsCheckmate(true) {
		c.Checkmate[0] = true
	}
	if c.Act && c.IsCheckmate(false) {
		c.Checkmate[1] = true
	}

	// 下一个玩家操作，记录回合数
	if !c.Act {
		c.Round++
	}
	c.Act = !c.Act
}

func (c *ChessJPZ) PrintChess() {
	f := func(n int) string {
		str := fmt.Sprintf(" %d", n+1)
		if c.IsWhiteMove() && n == 0 || c.IsBlackMove() && n == -1 {
			str = strings.Replace(str, " ", "*", 1)
		}
		return str
	}

	splitStr := "  "
	for y := c.Height - 1; y >= 0; y-- {
		fmt.Print(f(y))
		for x := 0; x < c.Width; x++ {
			fmt.Print(splitStr)
			idx, _ := XYToIndex(c.Width, c.Height, x, y)
			value := c.Buf[idx]
			if value == "" {
				fmt.Print("--")
			} else {
				fmt.Print(value)
			}
			splitStr = " "
		}
		fmt.Println()
		splitStr = "  "
	}
	fmt.Print("  ")
	for x := 0; x < c.Width; x++ {
		fmt.Print(splitStr)
		fmt.Print(fmt.Sprintf(" %d", x+1))
		splitStr = " "
	}
	fmt.Println()
}

func (c *ChessJPZ) GenFenChessBoard() string {
	var build strings.Builder
	splitStr := ""
	emptyCnt := 0

	writeEmptyCount := func() {
		if emptyCnt > 0 {
			countStr := fmt.Sprintf("%d", emptyCnt)
			build.WriteString(countStr)
			emptyCnt = 0
		}
	}

	for y := c.Height - 1; y >= 0; y-- {
		build.WriteString(splitStr)
		for x := 0; x < c.Width; x++ {
			idx, _ := XYToIndex(c.Width, c.Height, x, y)
			value := c.Buf[idx]
			if value == "" {
				//build.WriteString("")
				emptyCnt++
			} else {
				writeEmptyCount()
				t := value[1:]
				c := value[:1]
				if c == "W" {
					build.WriteString(string(t))
				} else if c == "B" {
					build.WriteString(strings.ToLower(string(t)))
				}
			}
		}
		writeEmptyCount()
		splitStr = "/"
	}
	return build.String()
}

func (c *ChessJPZ) GenFenCastling() string {
	return "-" // 客户端需要支持王车易位走位后才可使用
	//var build strings.Builder
	//if this.castling[0] {
	//	build.WriteString("K")
	//}
	//if this.castling[1] {
	//	build.WriteString("Q")
	//}
	//if this.castling[2] {
	//	build.WriteString("k")
	//}
	//if this.castling[3] {
	//	build.WriteString("q")
	//}
	//str := build.String()
	//if len(str) == 0 {
	//	return "-"
	//}
	//return build.String()
}

func (c *ChessJPZ) GenFenCambodianMove() string {
	var build strings.Builder
	if c.CambodianMove[MoveWK] {
		build.WriteString("D")
	}
	if c.CambodianMove[MoveWM] {
		build.WriteString("E")
	}
	if c.CambodianMove[MoveBM] {
		build.WriteString("d")
	}
	if c.CambodianMove[MoveBK] {
		build.WriteString("e")
	}
	str := build.String()
	if len(str) == 0 {
		return "-"
	}
	return build.String()
}

func (c *ChessJPZ) GenFenEnPassant() string {
	return "-"
}

func (c *ChessJPZ) GenHalfRoundCount() string {
	return "0"
}

func (c *ChessJPZ) GenRoundCount() string {
	return fmt.Sprintf("%d", c.Round)
}

func (c *ChessJPZ) GenFen() string {
	var build strings.Builder
	build.WriteString("fen ")
	build.WriteString(c.GenFenChessBoard())
	build.WriteString(" ")
	build.WriteString(c.GetAct())
	build.WriteString(" ")
	build.WriteString(c.GenFenCambodianMove())
	build.WriteString(" ")
	build.WriteString(c.GenFenEnPassant())
	build.WriteString(" ")
	build.WriteString(c.GenHalfRoundCount())
	build.WriteString(" ")
	build.WriteString(c.GenRoundCount())
	return build.String()
}

func (c *ChessJPZ) UciTwoPosToIdxList(str string) []int64 {
	result := []int64{-1, -1}
	result[0] = c.UciOnePosToIdx(str[0:2])
	result[1] = c.UciOnePosToIdx(str[2:4]) // 这里出现过g5f6m这样的返回，暂时不清楚这个m表示的意义，是兵进行吃子造成的
	return result
}

func (c *ChessJPZ) UciOnePosToIdx(str string) int64 {
	x := int(strings.ToLower(str[:1])[0] - 'a')
	y, _ := strconv.Atoi(str[1:])
	y--
	idx := y*c.Width + x
	//fmt.Println("UciOnePosToIdx", str, x, y, idx)
	return int64(idx)
}

func (c *ChessJPZ) GetChessNum(piece Piece) int {
	n := 0
	for _, v := range c.Buf {
		if piece == v {
			n++
		}
	}
	return n
}

func (c *ChessJPZ) GetWhiteNum() int {
	n := 0
	for _, v := range c.Buf {
		if IsWhite(v) {
			n++
		}
	}
	return n
}

func (c *ChessJPZ) GetBlackNum() int {
	n := 0
	for _, v := range c.Buf {
		if IsBlack(v) {
			n++
		}
	}
	return n
}

func (c *ChessJPZ) Has(piece Piece) bool {
	for _, v := range c.Buf {
		if v == piece {
			return true
		}
	}
	return false
}

func (c *ChessJPZ) GetVariant() int {
	return c.Variant
}

func (c *ChessJPZ) SetChess(strings []string) {
	for k, v := range strings {
		c.Buf[k] = Piece(v)
	}
}

func (c *ChessJPZ) Set(bufStr []string, bufPiece []Piece, act string, castling []bool, cambodianMove []bool, enPassant int, round int) {
	//var buf2 []Piece
	//if len(bufStr) > 0 {
	//	buf2 = make([]Piece, len(bufStr))
	//	for x := 0; x < c.Width; x++ {
	//		for y := 0; y < c.Height; y++ {
	//			buf2[(c.Height-1-y)*c.Width+x] = Piece(bufStr[y*c.Width+x])
	//		}
	//	}
	//} else {
	//	buf2 = make([]Piece, len(bufPiece))
	//	for x := 0; x < c.Width; x++ {
	//		for y := 0; y < c.Height; y++ {
	//			buf2[(c.Height-1-y)*c.Width+x] = bufPiece[y*c.Width+x]
	//		}
	//	}
	//}

	if len(bufStr) > 0 {
		for k, v := range bufStr {
			c.Buf[k] = Piece(v)
		}
	}
	if len(bufPiece) > 0 {
		for k, v := range bufPiece {
			c.Buf[k] = v
		}
	}

	if act == "w" {
		c.Act = false
	} else if act == "b" {
		c.Act = true
	}

	if len(castling) == 4 {
		for k, v := range castling {
			c.Castling[k] = v
		}
	}

	if len(cambodianMove) == 4 {
		for k, v := range cambodianMove {
			c.CambodianMove[k] = v
		}
	}

	c.EnPassant = enPassant
	c.Round = round
}

func (c *ChessJPZ) Init() {
	c.Variant = ChessVarCambodian
	c.Width = 8
	c.Height = 8
	c.Count = c.Width * c.Height
	c.Act = false
	c.Round = 1

	if c.Buf == nil || len(c.Buf) != c.Count {
		c.Buf = make([]Piece, c.Count)
	}
	for x := 0; x < c.Width; x++ {
		for y := 0; y < c.Height; y++ {
			c.Buf[(c.Height-1-y)*c.Width+x] = pieceJPZ[y*c.Width+x]
		}
	}

	c.Castling = [4]bool{true, true, true, true}
	c.EnPassant = -1
	c.CambodianMove = [4]bool{true, true, true, true}
	c.Records = c.Records[:0]
	c.Check = [2]bool{false, false}
	c.Checkmate = [2]bool{false, false}
}

// GetWidth 获取棋盘的宽度
func (c *ChessJPZ) GetWidth() int {
	return c.Width
}

// GetHeight 获取棋盘的高度
func (c *ChessJPZ) GetHeight() int {
	return c.Height
}

// MoveR 获取某个位置的车能走的下一步位置
func (c *ChessJPZ) MoveR(x, y int) []*PositionPiece {
	// 坐标转换成索引
	index, err := XYToIndex(c.Width, c.Height, x, y)
	if err != nil {
		return nil
	}

	// 判断这个位置是不是车
	o := c.Buf[index]
	if !IsR(o) {
		return nil
	}

	var validMoves []*PositionPiece

	// 遍历四个方向
	for _, dir := range StraightDirections {
		dx, dy := dir.X, dir.Y
		newX, newY := x+dx, y+dy

		// 检查新位置是否在棋盘范围内
		for newX >= 0 && newX < c.Width && newY >= 0 && newY < c.Height {
			// 获取新位置的索引
			index, err := XYToIndex(c.Width, c.Height, newX, newY)
			if err != nil {
				break
			}

			// 获取新位置的棋子
			piece := c.Buf[index]

			if IsEmpty(piece) {
				// 记录位置
				validMoves = append(validMoves, &PositionPiece{Index: index})
			} else {
				if IsWhite(piece) != IsWhite(o) {
					validMoves = append(validMoves, &PositionPiece{Index: index, P: piece})
				}
				break
			}

			// 新位置是空的，继续向前走
			newX += dx
			newY += dy
		}
	}

	return validMoves
}

// MoveN 获取某个位置的马能走的下一步位置
func (c *ChessJPZ) MoveN(x, y int) []*PositionPiece {
	// 坐标转换成索引
	index, err := XYToIndex(c.Width, c.Height, x, y)
	if err != nil {
		return nil
	}

	// 判断这个位置是不是马
	o := c.Buf[index]
	if !IsN(o) {
		return nil
	}

	var validMoves []*PositionPiece

	for _, dir := range KnightDirections {
		dx, dy := dir.X, dir.Y
		newX, newY := x+dx, y+dy

		// 检查新位置是否在棋盘范围内
		if newX >= 0 && newX < c.Width && newY >= 0 && newY < c.Height {
			// 获取新位置的索引
			index, err := XYToIndex(c.Width, c.Height, newX, newY)
			if err == nil {
				// 获取新位置的棋子
				piece := c.Buf[index]

				if IsEmpty(piece) || (IsWhite(piece) != IsWhite(o)) {
					validMoves = append(validMoves, &PositionPiece{Index: index, P: piece})
				}
			}
		}
	}

	return validMoves
}

// MoveS 获取某个位置的象能走的下一步位置
func (c *ChessJPZ) MoveS(x, y int) []*PositionPiece {
	// 坐标转换成索引
	index, err := XYToIndex(c.Width, c.Height, x, y)
	if err != nil {
		return nil
	}

	// 判断这个位置是不是象
	o := c.Buf[index]
	if !IsS(o) {
		return nil
	}

	var validMoves []*PositionPiece

	directions := QueenDirections
	if IsWhite(o) {
		directions = append(directions, Position{Y: 1})
	} else {
		directions = append(directions, Position{Y: -1})
	}

	// 遍历象的移动方向
	for _, dir := range directions {
		dx, dy := dir.X, dir.Y
		newX, newY := x+dx, y+dy

		// 检查新位置是否在棋盘范围内
		if newX >= 0 && newX < c.Width && newY >= 0 && newY < c.Height {
			// 获取新位置的索引
			index, err := XYToIndex(c.Width, c.Height, newX, newY)
			if err == nil {
				// 获取新位置的棋子
				piece := c.Buf[index]

				if IsEmpty(piece) || (IsWhite(piece) != IsWhite(o)) {
					validMoves = append(validMoves, &PositionPiece{Index: index, P: piece})
				}
			}
		}
	}

	return validMoves
}

// MoveM 获取某个位置的士能走的下一步位置
func (c *ChessJPZ) MoveM(x, y int) []*PositionPiece {
	// 坐标转换成索引
	index, err := XYToIndex(c.Width, c.Height, x, y)
	if err != nil {
		return nil
	}

	// 判断这个位置是不是士
	o := c.Buf[index]
	if !IsM(o) {
		return nil
	}

	var validMoves []*PositionPiece

	for _, dir := range QueenDirections {
		dx, dy := dir.X, dir.Y
		newX, newY := x+dx, y+dy

		// 检查新位置是否在棋盘范围内
		if newX >= 0 && newX < c.Width && newY >= 0 && newY < c.Height {
			// 获取新位置的索引
			index, err := XYToIndex(c.Width, c.Height, newX, newY)
			if err == nil {
				// 获取新位置的棋子
				piece := c.Buf[index]

				if IsEmpty(piece) || (IsWhite(piece) != IsWhite(o)) {
					validMoves = append(validMoves, &PositionPiece{Index: index, P: piece})
				}
			}
		}
	}

	if IsWhite(o) && c.CambodianMove[MoveWM] && index == 4 {
		index, err = XYToIndex(c.Width, c.Height, x, y+2)
		if err == nil && IsEmpty(c.Buf[index]) {
			validMoves = append(validMoves, &PositionPiece{Index: index})
		}
	}
	if IsBlack(o) && c.CambodianMove[MoveBM] && index == 59 {
		index, err = XYToIndex(c.Width, c.Height, x, y-2)
		if err == nil && IsEmpty(c.Buf[index]) {
			validMoves = append(validMoves, &PositionPiece{Index: index})
		}
	}

	return validMoves
}

// MoveK 获取某个位置的王能走的下一步位置
func (c *ChessJPZ) MoveK(x, y int) []*PositionPiece {
	// 坐标转换成索引
	i, err := XYToIndex(c.Width, c.Height, x, y)
	if err != nil {
		return nil
	}

	// 判断这个位置是不是王
	o := c.Buf[i]
	if !IsK(o) {
		return nil
	}

	var validMoves []*PositionPiece

	for _, dir := range KingDirections {
		dx, dy := dir.X, dir.Y
		newX, newY := x+dx, y+dy

		// 检查新位置是否在棋盘范围内
		if newX >= 0 && newX < c.Width && newY >= 0 && newY < c.Height {
			// 获取新位置的索引
			index, err := XYToIndex(c.Width, c.Height, newX, newY)
			if err == nil {
				// 获取新位置的棋子
				piece := c.Buf[index]

				if IsEmpty(piece) || (IsWhite(piece) != IsWhite(o)) {
					validMoves = append(validMoves, &PositionPiece{Index: index, P: piece})
				}
			}
		}
	}

	// 没有移动过，不能被将军，不能有棋子
	if IsWhite(o) && c.CambodianMove[MoveWK] {
		if !c.IsCheck(false) {
			//index, err := XYToIndex(c.Width, c.Height, x-1, y+2)
			//if err == nil && IsEmpty(c.Buf[index]) {
			//	validMoves = append(validMoves, &PositionPiece{Index: index})
			//}
			//index, err = XYToIndex(c.Width, c.Height, x+1, y+2)
			//if err == nil && IsEmpty(c.Buf[index]) {
			//	validMoves = append(validMoves, &PositionPiece{Index: index})
			//}
			index, err := XYToIndex(c.Width, c.Height, x-2, y+1)
			if err == nil && IsEmpty(c.Buf[index]) {
				validMoves = append(validMoves, &PositionPiece{Index: index})
			}
			index, err = XYToIndex(c.Width, c.Height, x+2, y+1)
			if err == nil && IsEmpty(c.Buf[index]) {
				validMoves = append(validMoves, &PositionPiece{Index: index})
			}
		}
	}
	// 没有移动过，不能被将军，不能有棋子
	if IsBlack(o) && c.CambodianMove[MoveBK] {
		// 不能被将军，不能有棋子
		if !c.IsCheck(true) {
			//index, err := XYToIndex(c.Width, c.Height, x-1, y-2)
			//if err == nil && IsEmpty(c.Buf[index]) {
			//	validMoves = append(validMoves, &PositionPiece{Index: index})
			//}
			//index, err = XYToIndex(c.Width, c.Height, x+1, y-2)
			//if err == nil && IsEmpty(c.Buf[index]) {
			//	validMoves = append(validMoves, &PositionPiece{Index: index})
			//}
			index, err := XYToIndex(c.Width, c.Height, x-2, y-1)
			if err == nil && IsEmpty(c.Buf[index]) {
				validMoves = append(validMoves, &PositionPiece{Index: index})
			}
			index, err = XYToIndex(c.Width, c.Height, x+2, y-1)
			if err == nil && IsEmpty(c.Buf[index]) {
				validMoves = append(validMoves, &PositionPiece{Index: index})
			}
		}
	}

	// 移动之后不能被将军
	var moves []*PositionPiece
	for _, v := range validMoves {
		c.Move(i, v.Index)
		if IsWhite(o) {
			if !c.IsCheck(false) {
				moves = append(moves, v)
			}
		} else {
			if !c.IsCheck(true) {
				moves = append(moves, v)
			}
		}
		c.MoveBack()
	}

	return moves
}

// MoveP 获取某个位置的兵能走的下一步位置
func (c *ChessJPZ) MoveP(x, y int) []*PositionPiece {
	// 坐标转换成索引
	index, err := XYToIndex(c.Width, c.Height, x, y)
	if err != nil {
		return nil
	}

	// 判断这个位置是不是兵
	o := c.Buf[index]
	if !IsP(o) {
		return nil
	}

	var validMoves []*PositionPiece

	newY := y
	isWhite := IsWhite(o)
	if isWhite {
		newY++
	} else {
		newY--
	}

	// 前进一格
	index, err = XYToIndex(c.Width, c.Height, x, newY)
	if err == nil && IsEmpty(c.Buf[index]) {
		validMoves = append(validMoves, &PositionPiece{Index: index})
	}

	// 斜吃
	index, err = XYToIndex(c.Width, c.Height, x-1, newY)
	if err == nil && !IsEmpty(c.Buf[index]) && IsWhite(c.Buf[index]) != isWhite {
		validMoves = append(validMoves, &PositionPiece{Index: index, P: c.Buf[index]})
	}
	index, err = XYToIndex(c.Width, c.Height, x+1, newY)
	if err == nil && !IsEmpty(c.Buf[index]) && IsWhite(c.Buf[index]) != isWhite {
		validMoves = append(validMoves, &PositionPiece{Index: index, P: c.Buf[index]})
	}

	return validMoves
}

func (c *ChessJPZ) movePositions(index int, flag bool) []*PositionPiece {
	x, y, err := IndexToXY(c.Width, c.Height, index)
	if err != nil {
		return nil
	}

	o := c.Buf[index]
	if IsEmpty(o) {
		return nil
	}

	var moves []*PositionPiece
	switch o {
	case WR, BR:
		moves = c.MoveR(x, y)
	case WN, BN:
		moves = c.MoveN(x, y)
	case WS, BS:
		moves = c.MoveS(x, y)
	case WM, BM:
		moves = c.MoveM(x, y)
	case WK, BK:
		moves = c.MoveK(x, y)
	case WP, BP:
		moves = c.MoveP(x, y)
	}

	// 被将军必须应将,走子后不能被将军
	if !flag {
		return moves
	}
	var moves2 []*PositionPiece
	for _, v := range moves {
		c.Move(index, v.Index)
		if IsWhite(o) && c.IsCheck(false) || IsBlack(o) && c.IsCheck(true) {
			c.MoveBack()
			continue
		}
		c.MoveBack()
		moves2 = append(moves2, v)
	}

	return moves2
}

// GetMovePositions 获取指定索引位置的棋子能走的位置
func (c *ChessJPZ) GetMovePositions(index int) []*PositionPiece {
	return c.movePositions(index, true)
}

func (c *ChessJPZ) IsWhiteMove() bool {
	return !c.Act
}

func (c *ChessJPZ) IsBlackMove() bool {
	return c.Act
}

// GetIndexes 获取指定棋子的位置
func (c *ChessJPZ) GetIndexes(p Piece) []int {
	var positions []int
	for k, v := range c.Buf {
		if v == p {
			positions = append(positions, k)
		}
	}
	return positions
}

// IsCheck 判断将军
func (c *ChessJPZ) IsCheck(isWhite bool) bool {
	for k, v := range c.Buf {
		if IsEmpty(v) || IsWhite(v) != isWhite {
			continue
		}
		if !IsK(v) {
			for _, vv := range c.movePositions(k, false) {
				if IsK(vv.P) {
					return true
				}
			}
		} else {
			// 白王是否吃黑王
			x, y, _ := IndexToXY(c.Width, c.Height, k)
			for _, dir := range KingDirections {
				dx, dy := dir.X, dir.Y
				newX, newY := x+dx, y+dy

				// 检查新位置是否在棋盘范围内
				if newX >= 0 && newX < c.Width && newY >= 0 && newY < c.Height {
					// 获取新位置的索引
					index, err := XYToIndex(c.Width, c.Height, newX, newY)
					if err == nil {
						if IsK(c.Buf[index]) {
							return true
						}
					}
				}
			}
		}
	}
	return false
}

// IsCheckmate 判断将死
func (c *ChessJPZ) IsCheckmate(isWhite bool) bool {
	if !c.IsCheck(isWhite) {
		return false
	}
	// 走任何一步，都将军
	for k, v := range c.Buf {
		if !IsEmpty(v) && IsWhite(v) != isWhite {
			for _, vv := range c.movePositions(k, false) {
				c.Move(k, vv.Index)
				if !c.IsCheck(isWhite) {
					c.MoveBack()
					return false
				}
				c.MoveBack()
			}
		}
	}

	return true
}

// CanMove 判断是否可以移动
func (c *ChessJPZ) CanMove(fromIndex, toIndex int) bool {
	if fromIndex < 0 || fromIndex >= len(c.Buf) || toIndex < 0 || toIndex >= len(c.Buf) {
		return false
	}

	if fromIndex == toIndex {
		return false
	}

	from := c.Buf[fromIndex]
	if IsEmpty(from) {
		return false
	}

	// 检查操作权
	if c.Act == IsWhite(from) {
		return false
	}

	list := c.GetMovePositions(fromIndex)
	for _, v := range list {
		if v.Index == toIndex {
			return true
		}
	}

	return false
}

// Move 移动棋子
func (c *ChessJPZ) Move(fromIndex, toIndex int) *PositionPiece {
	if fromIndex < 0 || fromIndex >= len(c.Buf) || toIndex < 0 || toIndex >= len(c.Buf) {
		return nil
	}

	if fromIndex == toIndex {
		return nil
	}

	from := c.Buf[fromIndex]
	if IsEmpty(from) {
		return nil
	}

	fromPiece := &PositionPiece{
		Index: fromIndex,
		P:     c.Buf[fromIndex],
	}
	to := &PositionPiece{
		Index: toIndex,
		P:     c.Buf[toIndex],
	}

	c.Records = append(c.Records, &RecordJPZ{
		FromTo:        [2]*PositionPiece{fromPiece, to},
		CambodianMove: c.CambodianMove,
	})

	// 王，士移动
	switch fromPiece.P {
	case WK:
		if c.CambodianMove[MoveWK] {
			c.CambodianMove[MoveWK] = false
		}
	case BK:
		if c.CambodianMove[MoveBK] {
			c.CambodianMove[MoveBK] = false
		}
	case WM:
		if c.CambodianMove[MoveWM] && fromIndex == 4 {
			c.CambodianMove[MoveWM] = false
		}
	case BM:
		if c.CambodianMove[MoveBM] && fromIndex == 59 {
			c.CambodianMove[MoveBM] = false
		}
	}

	// 兵升士
	if IsP(fromPiece.P) {
		_, y, err := IndexToXY(c.Width, c.Height, toIndex)
		if err == nil {
			if IsBlack(fromPiece.P) {
				if y == 2 {
					c.Buf[fromIndex] = BM
				}
			} else {
				if y == 5 {
					c.Buf[fromIndex] = WM
				}
			}
		}
	}

	c.Buf[toIndex] = c.Buf[fromIndex]
	c.Buf[fromIndex] = ""
	return to
}

// MoveBack 悔棋一步
func (c *ChessJPZ) MoveBack() bool {
	if len(c.Records) == 0 {
		return false
	}

	record := c.Records[len(c.Records)-1]
	c.Records = c.Records[:len(c.Records)-1]

	c.CambodianMove = record.CambodianMove
	c.Buf[record.FromTo[0].Index] = record.FromTo[0].P
	c.Buf[record.FromTo[1].Index] = record.FromTo[1].P
	return true
}

// IsStop 是否无子可走
func (c *ChessJPZ) IsStop(isWhite bool) bool {
	for k, v := range c.Buf {
		if !IsEmpty(v) && IsWhite(v) == isWhite {
			if len(c.GetMovePositions(k)) > 0 {
				return false
			}
		}
	}

	return true
}

// GetMoveAllPositions 所有可移动棋子及位置
func (c *ChessJPZ) GetMoveAllPositions(isWhite bool) [][2]*PositionPiece {
	var positions [][2]*PositionPiece
	for k, v := range c.Buf {
		if !IsEmpty(v) && IsWhite(v) == isWhite {
			for _, p := range c.GetMovePositions(k) {
				positions = append(positions, [2]*PositionPiece{{
					Index: k,
					P:     v,
				}, p})
			}
		}
	}
	return positions
}
