public void generate(List <sbyte> customPlacements = null) { //Destroy existing squares before we generate the new squares to fit the new board width and height. _destroyChildren(boardScript.chessPieceHolder); _destroyChildren(boardScript.chessSquareHolder); // Debug.Log("boardscript "+boardScript.chessSquareHolder); ////Add placemetns for the tiny board as is available from cgMenuScript //cgCustomBoardSettings.AddPiecePlacement(6, 7, new List<sbyte>{ // -2,-3,-5,-6,-3,-2, // -1,-1,-1,-1,-1,-1, // 0, 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, 0, // 0, 0, 0, 0, 0, 0, // 1, 1, 1, 1, 1, 1, // 2, 3, 5, 6, 3, 2 // }); _piecePlacements = customPlacements;// cgCustomBoardSettings.GetPiecePlacements(this.boardWidth, this.boardHeight); Debug.Log("piece placements " + _piecePlacements.Count); _board = new global::cgBoard(_piecePlacements, boardWidth, boardHeight); byte totalSquareCount = (byte)(boardWidth * boardHeight); List <cgSquareScript> squares = new List <cgSquareScript>(); for (byte b = 0; b < totalSquareCount; b++) { float y = Mathf.Floor(b / boardWidth); float x = b - (y * boardWidth); bool black = (b + y) % 2 == 0; GameObject newSquare = (GameObject)PrefabUtility.InstantiatePrefab(black ? blackSquarePrefab : whiteSquarePrefab); newSquare.transform.SetParent(boardScript.chessSquareHolder.transform); y *= squareSpacing.y; x *= squareSpacing.x; y = -y; newSquare.transform.localScale = new Vector3(squareScale.x, squareScale.y, newSquare.transform.localScale.z); newSquare.transform.localPosition = new Vector3(x + squareStartPoint.x, y - squareStartPoint.y, squareStartPoint.z); newSquare.GetComponent <cgSquareScript>().uniqueName = _board.SquareNames[b]; //UnityEngine.Debug.Log("Scale: "+newSquare.transform.localScale); squares.Add(newSquare.GetComponent <cgSquareScript>()); //newSquare.GetComponentInChildren<TextMesh>().text= b.ToString(); //newSquare.GetComponentInChildren<TextMesh>().GetComponent<MeshRenderer>().sortingOrder = 9; } for (byte b = 0; b < _piecePlacements.Count; b++) { if (_piecePlacements[b] != 0) { //Create a piece and place it accordingly. cgChessPieceScript piece = ((GameObject)PrefabUtility.InstantiatePrefab(piecePrefab)).GetComponent <cgChessPieceScript>(); piece.SetType(_piecePlacements[b]); piece.transform.SetParent(boardScript.chessPieceHolder.transform); } } boardScript.displayAs3d = use3d; boardScript.setBoardTo(_board); //We delay the start by 1 frame to allow unity garbage collector to destroy and remove any gameobjects that we've destroyed in this scope. //StartCoroutine(_startNextFrame(_board)); }
/// <summary> /// Notates the a game from the provided board. /// </summary> /// <param name="fromBoard">The board containing all moves to be notated</param> public cgNotation(cgBoard fromBoard) { foreach (cgSimpleMove move in fromBoard.moves) { AddMove(move); } }
public void Init(string _libName, string _lineName) { lineName = _lineName; line = ctGameManager.Singleton.GetLine(_libName, _lineName); if (line == null) { return; } Lbl_Title.text = string.Format("{0}/{1}", line.parent.name, _lineName); curMove = 0; isChanged = false; moveList.Clear(); for (int i = 0; i < line.moveList.Count; i++) { moveList.Add(line.moveList[i]); } board = new cgBoard(); InitCtrls(); UpdateInfos(); Wnd_Board.Init(board, WndBoard.CanMove.All, OnPieceMove); }
void startNewLine() { m_CurMoveIdx = 0; m_CurLine = m_LineList[m_CurLineIdx]; m_Board = new cgBoard(); Wnd_Board.Init(m_Board, m_PlayAsWhite ? WndBoard.CanMove.White : WndBoard.CanMove.Black, OnPieceMove); if (!m_PlayAsWhite) { Wnd_Board.FlipBoard(true); } m_Score = 0; m_MaxScore = CalcMaxScore(m_CurLine); m_MissedThisLine = false; m_Missed = false; Lbl_LineName.text = string.Format("{0}/{1} ({2})", m_CurLine.parent.name, m_CurLine.name, m_CurLine.moveList.Count); if (!m_PlayAsWhite) { Invoke("moveComputerMove", 1.5f); } else { UpdateInfos(); } }
public void Init(cgBoard _board, CanMove _canMove, PieceMoveHandler _handler) { m_Board = _board; m_CanMove = _canMove; m_PieceMoveHandler = _handler; FlipBoard(false); UpdateBoard(); }
/// <summary> /// Paste the game notation from clipboard onto the board. /// </summary> private void _pasteGameFromClipboard() { string curgame = GUIUtility.systemCopyBuffer; _abstractBoard = new cgBoard(); Debug.Log("Pasted game from clipboard: " + curgame); cgNotation notation = new cgNotation(_abstractBoard); notation.Read(curgame); _abstractBoard.LoadGame(notation); _setBoardTo(_abstractBoard); }
/// <summary> /// Called when the engine should generate a new move. /// </summary> /// <param name="board">The current board state.</param> /// <param name="MoveAsWhiteP">Move as white(true) or black(false).</param> /// <param name="callback">Where the prefered move will be returned.</param> public void MakeMove(cgBoard board, bool MoveAsWhiteP, Action <cgSimpleMove> callback) { //stopwatch = new Stopwatch(); //stopwatch.Start(); Finished = false; _board = board; MoveAsWhite = MoveAsWhiteP; _callback = callback; StartCoroutine(_startAnalysis()); }
/// <summary> /// Called when the engine should generate a new move. /// </summary> /// <param name="board">The current board state.</param> /// <param name="moveAsWhiteP">Move as white(true) or black(false).</param> /// <param name="callback">Where the prefered move will be returned.</param> public void MakeEngineMove(cgBoard board, bool moveAsWhiteP, Action <List <cgSimpleMove> > callback) { _engineCallbackFunctions = new List <Action <List <cgSimpleMove> > >(); _engineCallbackFunctions.Add(callback); UnityEngine.Debug.Log("Making engine move, with multithreading: " + useMultiThreading); if (useMultiThreading) { this._makeEngineMoveMulti(board, moveAsWhiteP, callback); } else { this._makeEngineMoveMono(board, moveAsWhiteP, callback); } }
public void makeMoveMono(Action <IEnumerator> startCoroutine, cgBoard board, bool moveAsWhiteP, Action <List <cgSimpleMove> > completeCallback, Action <float> progressCallback = null) { _verifyValueModifierSizes(board.squares); //stopwatch = new Stopwatch(); //stopwatch.Start(); //Console.WriteLine("engine making move"); finished = false; _board = board; moveAsWhite = moveAsWhiteP; _callback = completeCallback; startCoroutine(_startAnalysis(progressCallback)); }
/// <summary> /// Resets the board, called by the menu button called restart. /// </summary> public void ResetBoard() { //UnityEngine.Debug.Log("reset"); cgBoard newboard = _abstractBoard.duplicate().revertToStart(); if (_gameOverScreen != null) { //UnityEngine.Debug.Log("destroying:" + _gameOverScreen); GameObject.Destroy(_gameOverScreen); _gameOverScreen = null; } start(newboard, Mode); }
/// <summary> /// Called when the engine should generate a new move. /// </summary> /// <param name="board">The current board state.</param> /// <param name="MoveAsWhiteP">Move as white(true) or black(false).</param> /// <param name="completeCallback">Where the prefered move will be returned.</param> public void makeMove(cgBoard board, bool moveAsWhiteP, Action <List <cgSimpleMove> > completeCallback, Action <float> progressCallback = null) { _verifyValueModifierSizes(board.squares); //stopwatch = new Stopwatch(); //stopwatch.Start(); //UnityEngine.Debug.Log("Engine making move."); Console.WriteLine("engine making move"); finished = false; _board = board; moveAsWhite = moveAsWhiteP; _callback = completeCallback; for (var e = _startAnalysis(progressCallback); e.MoveNext();) { } }
/// <summary> /// Set the board to the provided abstract board, write any moves provided in said abstract board to the log, etc. /// </summary> /// <param name="board"></param> private void _setBoardTo(cgBoard board) { _abstractBoard = board; _livePieces = new List <cgChessPieceScript>(); _deadPieces = new List <cgChessPieceScript>(); _deadWhitePieces = 0; _deadBlackPieces = 0; movesMade = _abstractBoard.moves.Count; moveLog.text = "Moves: \n"; _loggedMoves = 0; foreach (cgSimpleMove move in board.moves) { _writeLog(move); } whiteTurnToMove = _abstractBoard.whiteTurnToMove; _placePieces(); }
/// <summary> /// Called when the engine should generate a new move using corutine on a singlethread(mono threaded). /// </summary> /// <param name="board">The current board state.</param> /// <param name="moveAsWhiteP">Move as white(true) or black(false).</param> /// <param name="callback">Where the prefered move will be returned.</param> public void _makeEngineMoveMono(cgBoard board, bool moveAsWhiteP, Action <List <cgSimpleMove> > callback) { Action <List <cgSimpleMove> > completeCallback = (List <cgSimpleMove> moves) => { //print("compelte callback: " + moves.Count); //System.Reflection.MethodBase.Invoke(new Action(()=> _threadCallback(),null); lock (_engineCallbackParams) { UnityEngine.Debug.Log("Callback and added moves: " + moves.Count); _engineCallbackParams.Add(moves); } }; Action <float> progessCallback = (float progress) => { //UnityEngine.Debug.Log("Progress registered. " + progress); lock (_engineProgress) { _engineProgress.Add(progress); } }; _engine.makeMoveMono(this._startCoroutine, board, moveAsWhiteP, completeCallback, progessCallback); }
/// <summary> /// Start the game, with provided board. /// </summary> /// <param name="customBoard">The abstract board that we should match, if none specified we use existing one, if none exists we generate an 8x8 board</param> /// <param name="mode">Which mode the game is in, player vs player, player vs engine, engine vs engine etc.</param> public void start(cgBoard customBoard = null, BoardMode mode = BoardMode.Undefined) { if (customBoard == null) { if (this._abstractBoard != null) { customBoard = this._abstractBoard; } else { customBoard = new global::cgBoard(); } } if (displayAs3d) { Camera.main.transform.localPosition = new Vector3(0, -2.28f, -12.58f); Quaternion newQuat = Camera.main.transform.localRotation; newQuat = Quaternion.Euler(-23.46f, newQuat.eulerAngles.y, newQuat.eulerAngles.z); Camera.main.transform.localRotation = newQuat; } //customBoard = customBoard.revertToStart(); UnityEngine.Debug.Log("start: "); _squares = getSquares(); Mode = (mode != BoardMode.Undefined ? mode : Mode); _engine = new cgEngine(searchDepthWeak, searchDepthStrong); setBoardTo(customBoard); //_abstractBoard.readBoard(); // UnityEngine.Debug.Log(_abstractBoard.boardToString()); if (Mode == BoardMode.PlayerVsEngine && !whiteTurnToMove) { MakeEngineMove(_abstractBoard.duplicate(), false, _engineCallback); } else if (Mode == BoardMode.EngineVsPlayer && whiteTurnToMove) { MakeEngineMove(_abstractBoard.duplicate(), true, _engineCallback); } else if (Mode == BoardMode.EngineVsEngine) { MakeEngineMove(_abstractBoard.duplicate(), true, _engineCallback); } }
/// <summary> /// Called when the engine should generate a new move using a new thread(multi threaded).. /// </summary> /// <param name="board">The current board state.</param> /// <param name="moveAsWhiteP">Move as white(true) or black(false).</param> /// <param name="callback">Where the prefered move will be returned.</param> private void _makeEngineMoveMulti(cgBoard board, bool moveAsWhiteP, Action <List <cgSimpleMove> > callback) { if (_engineThread != null) { _engineThread.CancelAsync(); } _engineThread = new BackgroundWorker(); //The thread for the engine to make its computations to decide on a move using a new thread(multi threaded). Action <object, DoWorkEventArgs> _threadMakeMove = (object sender, DoWorkEventArgs e) => { Action <List <cgSimpleMove> > completeCallback = (List <cgSimpleMove> moves) => { //print("compelte callback: " + moves.Count); //System.Reflection.MethodBase.Invoke(new Action(()=> _threadCallback(),null); lock (_engineCallbackParams) { _engineCallbackParams.Add(moves); } }; Action <float> progessCallback = (float progress) => { //UnityEngine.Debug.Log("Progress registered. " + progress); lock (_engineProgress) { _engineProgress.Add(progress); } }; _engine.makeMove(board, moveAsWhiteP, completeCallback, progessCallback); }; _engineThread.DoWork += new DoWorkEventHandler(_threadMakeMove); //Thread _engineThread = new Thread(_threadMakeMove); _engineThread.RunWorkerCompleted += _engineThread_RunWorkerCompleted; _engineThread.ProgressChanged += _engineThread_ProgressChanged; _engineThread.WorkerSupportsCancellation = true; UnityEngine.Debug.Log("Starting thread."); //(board, moveAsWhiteP, callback _engineThread.RunWorkerAsync(); }
/// <summary> /// Writes the full game notation from the current moves stored in Moves list. /// </summary> /// <param name="type">What notationtype should it be?</param> /// <param name="formatType">Should it be PGN format or not?</param> /// <returns>A string with full game notation.</returns> public string writeFullNotation(NotationType type, FormatType formatType = FormatType.None) { string str = ""; cgBoard disambiguationBoard = board.duplicate().revertToStart(); if (type == NotationType.Coordinate) { foreach (cgSimpleMove pcem in moves) { str += (disambiguationBoard.SquareNames[pcem.from] + "-" + disambiguationBoard.SquareNames[pcem.to]) + " "; } } if (formatType == FormatType.PGN) { string q = "\""; str = " [Event " + q + "Pro Chess" + q + "]\n"; str += " [Site " + q + "Undefined site" + q + "]\n"; str += " [Date " + q + DateTime.Now + q + "]\n"; str += " [White " + q + "Chessplayer1" + q + "]\n"; str += " [Black " + q + "Chessplayer2" + q + "]\n"; str += " [Result " + q + "1/2-1/2" + q + "]\n"; } if (type == NotationType.Algebraic) { foreach (cgSimpleMove pcem in moves) { if (disambiguationBoard.moves.Count % 2 == 0) { str += (Math.Floor(disambiguationBoard.moves.Count / 2f) + 1).ToString() + ". "; } int typ = Math.Abs(disambiguationBoard.squares[pcem.from]); List <cgSimpleMove> othermoves = disambiguationBoard.findLegalMoves(disambiguationBoard.whiteTurnToMove); List <cgSimpleMove> ambiguousMoves = new List <cgSimpleMove>(); foreach (cgSimpleMove othermove in othermoves) { if (othermove.to == pcem.to && othermove.from != pcem.from && Math.Abs(disambiguationBoard.squares[othermove.from]) == typ) { ambiguousMoves.Add(othermove); } } if (typ == 1 && pcem.capturedType != 0) { str += disambiguationBoard.SquareNames[pcem.from].Substring(0, 1); } if (typ == 2) { str += "R"; } if (typ == 3) { str += "N"; } if (typ == 4) { str += "B"; } if (typ == 5) { str += "Q"; } if (typ == 6 && !(pcem is cgCastlingMove)) { str += "K"; } //if (typ == 6) str += "K"; if (ambiguousMoves.Count > 0 && typ != 1) { bool fileMatch = false; bool rankMatch = false; foreach (cgSimpleMove ambiguousMove in ambiguousMoves) { if (disambiguationBoard.SquareNames[ambiguousMove.from].Substring(0, 1) == disambiguationBoard.SquareNames[pcem.from].Substring(0, 1)) { fileMatch = true; } if (disambiguationBoard.SquareNames[ambiguousMove.from].Substring(1, 1) == disambiguationBoard.SquareNames[pcem.from].Substring(1, 1)) { rankMatch = true; } } if (!fileMatch) { str += disambiguationBoard.SquareNames[pcem.from].Substring(0, 1); } else if (fileMatch && !rankMatch) { str += disambiguationBoard.SquareNames[pcem.from].Substring(1, 1); } else if (fileMatch && rankMatch) { str += disambiguationBoard.SquareNames[pcem.from]; } } if (pcem.capturedType != 0) { str += "x"; } if (pcem is cgCastlingMove) { if (pcem.to == 2 || pcem.to == 58) { str += "O-O-O"; } else { str += "O-O"; } } else { str += disambiguationBoard.SquareNames[pcem.to]; } if (pcem.queened) { str += "=Q"; } str += " "; disambiguationBoard.move(pcem); } } return(str); }
/// <summary> /// Read the notations in the provided string. /// </summary> /// <param name="curgame">the string to decipher.</param> public void Read(string curgame) { int lastIndex = 0; int nextIndex = 0; string move = curgame.Substring(lastIndex, nextIndex); NotationType ntype = NotationType.Algebraic; //= NotationType.Coordinate; //Debug.Log("first move:" + move); //if (move.Contains("-")) ntype = NotationType.Coordinate; moves = new List <cgSimpleMove>(); if (ntype == NotationType.Coordinate) { while (lastIndex != -1) { byte fromp = board.IndexFromCellName(move.Substring(0, 2)); byte top = board.IndexFromCellName(move.Substring(3, 2)); moves.Add(new cgSimpleMove(fromp, top)); nextIndex = curgame.IndexOf(" ", lastIndex + 1); if (nextIndex == -1) { break; } move = curgame.Substring(lastIndex + 1, nextIndex - lastIndex); lastIndex = nextIndex; //Debug.Log("current move being analyzed="+move); } } else if (ntype == NotationType.Algebraic) { cgBoard disambBoard = new cgBoard(); cgSimpleMove chosenMove; while (lastIndex != -1) { chosenMove = null; nextIndex = curgame.IndexOf(" ", nextIndex + 1); if (nextIndex == -1 || lastIndex == -1) { break; } move = curgame.Substring(lastIndex + 1, nextIndex - lastIndex); bool legitMove = (!move.Contains(".") && move.Length > 1 && !move.Contains("\n")) ? true : false; move = move.Trim(' '); //move = move.Trim('\n'); //Debug.Log("trimmed:" + move+" contains .:"+move.Contains(".")+" contains newline:"+move.Contains("\n")+" legit move:"+legitMove); if (move.Contains("{")) { nextIndex = curgame.IndexOf("}", lastIndex + 1); } else if (move.Contains("[")) { nextIndex = curgame.IndexOf("]", lastIndex + 1); } else if (legitMove) { //Debug.Log("found to be legit move."); byte tosquare; byte pushback = 2; byte type = 1; //bool promotion = false; bool shortCastling = (move == "O-O"); bool longCastling = (move == "O-O-O"); if (move.Contains("=")) { //promotion = true; move.Remove(move.IndexOf("="), 2); } else if (move.Contains("+")) { move.Remove(move.IndexOf("+"), 1); } else if (move.Contains("!")) { move.Remove(move.IndexOf("!"), 1); } else if (move.Contains("?")) { move.Remove(move.IndexOf("?"), 1); } tosquare = board.IndexFromCellName(move.Substring(move.Length - pushback, 2)); if (move[0] == 'R') { type = 2; } if (move[0] == 'N') { type = 3; } if (move[0] == 'B') { type = 4; } if (move[0] == 'Q') { type = 5; } if (move[0] == 'K') { type = 6; } List <cgSimpleMove> ambiguousMoves = new List <cgSimpleMove>(); foreach (cgSimpleMove legalMove in disambBoard.findLegalMoves(disambBoard.whiteTurnToMove)) { if (shortCastling && legalMove is cgCastlingMove) { if (legalMove.to == 6 || legalMove.to == 62) { chosenMove = legalMove; break; } } else if (longCastling && legalMove is cgCastlingMove) { if (legalMove.to == 2 || legalMove.to == 58) { chosenMove = legalMove; break; } } if (Math.Abs(disambBoard.squares[legalMove.from]) == type && legalMove.to == tosquare) { ambiguousMoves.Add(legalMove); } } if (ambiguousMoves.Count == 0 && chosenMove == null) { //Debug.WriteLine("found no matching move for the string: " + move+" type:"+type+" tosquare:"+tosquare+" chosenMove:"+chosenMove+" castling:"+shortCastling); break; } else if (ambiguousMoves.Count == 1) { chosenMove = ambiguousMoves[0]; } else if (ambiguousMoves.Count > 1) { //UnityEngine.Debug.Log("2 or mroe ambiguousmoves"); //2 or more ambiguous moves in which the piece type matches and the destination square matches. Further disambiguation needed. List <cgSimpleMove> matching = new List <cgSimpleMove>(); foreach (cgSimpleMove mov in ambiguousMoves) { if (board.SquareNames[mov.from].Contains(move.Substring(1 + (type == 1?-1:0), 1))) { matching.Add(mov); } } if (matching.Count == 1) { chosenMove = matching[0]; //only 1 of the ambiguous moves have the correct rank and/or file. } else { foreach (cgSimpleMove mov in ambiguousMoves) { if (board.SquareNames[mov.from].Contains(move.Substring(1, 2))) { chosenMove = ambiguousMoves[0]; break; } } } } if (chosenMove != null) { disambBoard.move(chosenMove); moves.Add(chosenMove); } } Debug.WriteLine("legitmove:" + legitMove); lastIndex = nextIndex; } } }
public static string NotationFromMove(cgBoard _board, cgSimpleMove _move) { string str = ""; if (_board.moves.Count % 2 == 0) { str += (Math.Floor(_board.moves.Count / 2f) + 1).ToString() + ". "; } int typ = Mathf.Abs(_board.squares[_move.from]); List <cgSimpleMove> othermoves = _board.findLegalMoves(_board.whiteTurnToMove); List <cgSimpleMove> ambiguousMoves = new List <cgSimpleMove>(); foreach (cgSimpleMove othermove in othermoves) { if (othermove.to == _move.to && othermove.from != _move.from && Mathf.Abs(_board.squares[othermove.from]) == typ) { ambiguousMoves.Add(othermove); } } if (typ == 1 && _move.capturedType != 0) { str += cgGlobal.SquareNames[_move.from].Substring(0, 1); } if (typ == 2) { str += "R"; } if (typ == 3) { str += "N"; } if (typ == 4) { str += "B"; } if (typ == 5) { str += "Q"; } if (typ == 6 && !(_move is cgCastlingMove)) { str += "K"; } //if (typ == 6) str += "K"; if (ambiguousMoves.Count > 0 && typ != 1) { bool fileMatch = false; bool rankMatch = false; foreach (cgSimpleMove ambiguousMove in ambiguousMoves) { if (cgGlobal.SquareNames[ambiguousMove.from].Substring(0, 1) == cgGlobal.SquareNames[_move.from].Substring(0, 1)) { fileMatch = true; } if (cgGlobal.SquareNames[ambiguousMove.from].Substring(1, 1) == cgGlobal.SquareNames[_move.from].Substring(1, 1)) { rankMatch = true; } } if (!fileMatch) { str += cgGlobal.SquareNames[_move.from].Substring(0, 1); } else if (fileMatch && !rankMatch) { str += cgGlobal.SquareNames[_move.from].Substring(1, 1); } else if (fileMatch && rankMatch) { str += cgGlobal.SquareNames[_move.from]; } } if (_move.capturedType != 0) { str += "x"; } if (_move is cgCastlingMove) { if (_move.to == 2 || _move.to == 58) { str += "O-O-O"; } else { str += "O-O"; } } else { str += cgGlobal.SquareNames[_move.to]; } if (_move.promoted) { switch (_move.promotionType) { case 2: str += "=R"; break; case 3: str += "=N"; break; case 4: str += "=B"; break; case 5: str += "=Q"; break; default: break; } } return(str); }