[squeak-dev] The Trunk: EToys-mt.395.mcz

commits at source.squeak.org commits at source.squeak.org
Wed Jun 3 13:24:58 UTC 2020


Marcel Taeumel uploaded a new version of EToys to project The Trunk:
http://source.squeak.org/trunk/EToys-mt.395.mcz

==================== Summary ====================

Name: EToys-mt.395
Author: mt
Time: 3 June 2020, 3:24:51.881117 pm
UUID: b4c7142d-c357-3448-86fd-62a029de049d
Ancestors: EToys-mt.394

Fixes for the original chess game. Adds the revised version, Chess 960, to Etoys games catalogue. Also available through the parts bin. Thanks to Stéphane (spfa)!

Bugfixes:

- castling was not possible when a rook was menaced
- a test for king attack in black king-side castling was missing
- the cached number of pawns is sometimes off, which could lead to a
DivideByZero error in some endgames (this is fixed, but not the
discrepancy which still effects the material evaluation)
- a pawn taken en-passant was not removed from display

One notable bug left is that undoing a castling move makes it impossible
to castle again.

Improvements:

- nicer display, scalable (with assets from wikimedia common)
- the board is now sticky and cannot be accidentally grabbed
- hints (from the 'help' button) now appear in the status line
- support for Fischer randomized chess, aka Chess960

Changes:

- to castle, one now has to move the king over the rook

=============== Diff against EToys-mt.394 ===============

Item was changed:
  SystemOrganization addCategory: #'Etoys-Buttons'!
  SystemOrganization addCategory: #'Etoys-CustomEvents'!
  SystemOrganization addCategory: #'Etoys-Experimental'!
  SystemOrganization addCategory: #'Etoys-OLPC-Display'!
  SystemOrganization addCategory: #'Etoys-Outliner'!
  SystemOrganization addCategory: #'Etoys-Protocols'!
  SystemOrganization addCategory: #'Etoys-Protocols-Type Vocabularies'!
  SystemOrganization addCategory: #'Etoys-ReleaseBuilder'!
  SystemOrganization addCategory: #'Etoys-Scripting'!
  SystemOrganization addCategory: #'Etoys-Scripting Support'!
  SystemOrganization addCategory: #'Etoys-Scripting Tiles'!
  SystemOrganization addCategory: #'Etoys-Squeakland-BroomMorphs-Base'!
  SystemOrganization addCategory: #'Etoys-Squeakland-BroomMorphs-Connectors'!
  SystemOrganization addCategory: #'Etoys-Squeakland-EToys-Kedama'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Buttons'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Calendar'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Debugger'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Help'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Input'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting Support'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting Tiles'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-SpeechBubbles'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Tile Scriptors'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Text'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Intersection'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Simplification'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Triangulation'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Basic'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Books'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Components'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Demo'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Experimental'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Games'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Games-Chess'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-GeeMail'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Kernel'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Mentoring'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Navigators'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-PDA'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-PartsBin'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Support'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Widgets'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Windows'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Worlds'!
  SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-AdditionalMorphs'!
  SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Charts'!
  SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Postscript Filters'!
  SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-WebCam'!
  SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Widgets'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Multilingual-Languages'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Multilingual-TextConversion'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Formatter'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Forms'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Parser'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Parser Entities'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Tokenizer'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-MIME'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-TelNet WordNet'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-UI'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Network-Url'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Protocols-Type Vocabularies'!
  SystemOrganization addCategory: #'Etoys-Squeakland-SISS-Serialization'!
  SystemOrganization addCategory: #'Etoys-Squeakland-ST80-Morphic'!
  SystemOrganization addCategory: #'Etoys-Squeakland-SUnit'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Interface'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Ogg'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Scores'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Sugar'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Support'!
  SystemOrganization addCategory: #'Etoys-Squeakland-System-Clipboard-Extended'!
  SystemOrganization addCategory: #'Etoys-Squeakland-System-Compiler'!
  SystemOrganization addCategory: #'Etoys-Squeakland-System-Exceptions Kernel'!
  SystemOrganization addCategory: #'Etoys-Squeakland-System-Support'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Changes'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Explorer'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Process Browser'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ObjectVectors'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ParseTree-AttributeDefinition'!
  SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ParseTreeTransformer'!
  SystemOrganization addCategory: #'Etoys-Stacks'!
  SystemOrganization addCategory: #'Etoys-StarSqueak'!
  SystemOrganization addCategory: #'Etoys-Support'!
  SystemOrganization addCategory: #'Etoys-Tests'!
  SystemOrganization addCategory: #'Etoys-Tile Scriptors'!
  SystemOrganization addCategory: #'Etoys-UserInterfaceTheme'!
  SystemOrganization addCategory: #'Etoys-Widgets'!
+ SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Games-Chess960'!

Item was added:
+ ChessBoard subclass: #Chess960Board
+ 	instanceVariableNames: ''
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Etoys-Squeakland-Morphic-Games-Chess960'!
+ 
+ !Chess960Board commentStamp: 'spfa 6/2/2020 15:13' prior: 0!
+ Chess960Board can handle Fisher-style random starting positions in home ranks!

Item was added:
+ ----- Method: Chess960Board>>initialize (in category 'initialize') -----
+ initialize
+ 	generator ifNil:[generator := Chess960MoveGenerator new initialize].
+ 	searchAgent ifNil:[searchAgent := ChessPlayerAI new initialize].
+ 	self resetGame.
+ !

Item was added:
+ ----- Method: Chess960Board>>initializeNewBoard (in category 'initialize') -----
+ initializeNewBoard
+ 	
+ 	| conf |
+ 
+ 	self resetGame.
+ 	conf := Chess960Configuration new.
+ 	whitePlayer addWhitePieces: conf.
+ 	blackPlayer addBlackPieces: conf.
+ !

Item was added:
+ ----- Method: Chess960Board>>resetGame (in category 'initialize') -----
+ resetGame
+ 	hashKey := hashLock := 0.
+ 	whitePlayer := Chess960Player new initialize.
+ 	blackPlayer := Chess960Player new initialize.
+ 	whitePlayer opponent: blackPlayer.
+ 	whitePlayer board: self.
+ 	blackPlayer opponent: whitePlayer.
+ 	blackPlayer board: self.
+ 	activePlayer := whitePlayer.
+ 	searchAgent reset: self.
+ 	userAgent ifNotNil:[userAgent gameReset].!

Item was added:
+ Object subclass: #Chess960Configuration
+ 	instanceVariableNames: 'positions king leftRook rightRook'
+ 	classVariableNames: ''
+ 	poolDictionaries: 'ChessConstants'
+ 	category: 'Etoys-Squeakland-Morphic-Games-Chess960'!
+ 
+ !Chess960Configuration commentStamp: 'spfa 6/2/2020 15:13' prior: 0!
+ A Chess960Configuration is a Fisher-style random starting arrangement of pieces in the home ranks!

Item was added:
+ ----- Method: Chess960Configuration class>>new (in category 'as yet unclassified') -----
+ new
+ 
+ 	| rand positions k |
+ 
+ 	rand := Random new.
+ 	positions := Array new: 8.
+ 	positions at: (rand nextInt: 4) * 2 - 1 put: Bishop.
+ 	positions at: (rand nextInt: 4) * 2 put: Bishop.
+ 	positions at: (k := (((1 to: 8) select: [:n | (positions at: n) isNil]) copyFrom: 2 to: 5) atRandom: rand) put: King.
+ 	positions at: (((1 to: k-1) select: [:n | (positions at: n) isNil]) atRandom: rand) put: Rook.
+ 	positions at: (((k+1 to: 8) select: [:n | (positions at: n) isNil]) atRandom: rand) put: Rook.
+ 	positions at: (((1 to: 8) select: [:n | (positions at: n) isNil]) atRandom: rand) put: Queen.
+ 	positions at: ((1 to: 8) detect: [:n | (positions at: n) isNil]) put: Knight.
+ 	positions at: ((1 to: 8) detect: [:n | (positions at: n) isNil]) put: Knight.
+ 
+ 	^ self basicNew positions: positions
+ !

Item was added:
+ ----- Method: Chess960Configuration>>initialKingPosition (in category 'positions') -----
+ initialKingPosition
+ 
+ 	^ king ifNil: [king := positions indexOf: King]!

Item was added:
+ ----- Method: Chess960Configuration>>initialLeftRookPosition (in category 'positions') -----
+ initialLeftRookPosition
+ 
+ 	^ leftRook ifNil: [leftRook := positions indexOf: Rook]!

Item was added:
+ ----- Method: Chess960Configuration>>initialRightRookPosition (in category 'positions') -----
+ initialRightRookPosition
+ 
+ 	^ rightRook ifNil: [rightRook := positions indexOf: Rook startingAt: self initialKingPosition]!

Item was added:
+ ----- Method: Chess960Configuration>>positions (in category 'positions') -----
+ positions
+ 
+ 	^ positions!

Item was added:
+ ----- Method: Chess960Configuration>>positions: (in category 'positions') -----
+ positions: anArray
+ 
+ 	positions := anArray.
+ 	king := leftRook := rightRook := nil!

Item was added:
+ ChessMorph subclass: #Chess960Morph
+ 	instanceVariableNames: 'images message squareSize'
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Etoys-Squeakland-Morphic-Games-Chess960'!
+ 
+ !Chess960Morph commentStamp: 'spfa 6/2/2020 15:10' prior: 0!
+ Chess960Morph is a nicer, scalable, skin for ChessMorph.
+ It also can play Fischer random chess (use the '960' button) 
+ 
+ 	Chess960Morph new openInWorld
+ 
+ 	(Chess960Morph new squareSize: 100) openInWorld
+ !

Item was added:
+ ----- Method: Chess960Morph class>>descriptionForPartsBin (in category 'parts bin') -----
+ descriptionForPartsBin
+ 	^ self partName: 	'Chess 960' translatedNoop
+ 		categories:		{'Games' translatedNoop}
+ 		documentation:	'A fine game of chess. Revised by Stéphane Rollandin (spfa).' translatedNoop!

Item was added:
+ ----- Method: Chess960Morph>>addButtonRow (in category 'initialize') -----
+ addButtonRow
+ 
+ 	| r m |
+ 	r := AlignmentMorph newRow hResizing: #shrinkWrap; vResizing: #shrinkWrap; color: Color transparent.
+ 	r cellInset: 2.
+ 	r addMorphBack: (self buttonName: '  New  ' translated action: #newGame).
+ 	r addMorphBack: (self buttonName: '  960  ' translated action: #new960Game).
+ 	r addMorphBack: (self buttonName: '  Help  ' translated action: #findBestMove).
+ 	r addMorphBack: (self buttonName: '  Play  ' translated action: #thinkAndMove).
+ 	r addMorphBack: (self buttonName: '  Auto  ' translated action: #autoPlay).
+ 	r addMorphBack: (self buttonName: '  Undo  ' translated action: #undoMove).
+ 	r addMorphBack: (self buttonName: '  Redo  ' translated action: #redoMove).
+ 	r addMorphBack: (self buttonName: '  Quit  ' translated action: #delete).
+ 	r disableTableLayout: true.
+ 	r align: r bounds topLeft with: self layoutBounds topLeft.
+ 	self addMorphFront: r.
+ 	m := UpdatingStringMorph on: self selector: #statusString.
+ 	m useStringFormat.
+ 	m disableTableLayout: true.
+ 	m stepTime: 50.
+ 	m align: m bounds topLeft with: r fullBounds bottomLeft.
+ 	self addMorphFront: m.
+ 	m
+ 		font: self textFont; 
+ 		color: self statusColor; 
+ 		maximumWidth: self width - self squareSize; 
+ 		position:  self position + (self squareSize @ self squareSize * 0.6)!

Item was added:
+ ----- Method: Chess960Morph>>addSquares (in category 'initialize') -----
+ addSquares
+ 	| white black border square index |
+ 	white := self whiteColor.
+ 	black := self blackColor.
+ 	border := self highColor.
+ 	index := 0.
+ 	#(
+ 		(	' '	'a'	'b'	'c'	'd'	'e'	'f'	'g'	'h'	' ')
+ 		(	'1'	'B'	'W'	'B'	'W'	'B'	'W'	'B'	'W'	' ')
+ 		(	'2'	'W'	'B'	'W'	'B'	'W'	'B'	'W'	'B'	' ')
+ 		(	'3'	'B'	'W'	'B'	'W'	'B'	'W'	'B'	'W'	' ')
+ 		(	'4'	'W'	'B'	'W'	'B'	'W'	'B'	'W'	'B'	' ')
+ 		(	'5'	'B'	'W'	'B'	'W'	'B'	'W'	'B'	'W'	' ')
+ 		(	'6'	'W'	'B'	'W'	'B'	'W'	'B'	'W'	'B'	' ')
+ 		(	'7'	'B'	'W'	'B'	'W'	'B'	'W'	'B'	'W'	' ')
+ 		(	'8'	'W'	'B'	'W'	'B'	'W'	'B'	'W'	'B'	' ')
+ 		(	' '	' '	' '	' '	' '	' '	' '	' '	' '	' ')
+ 	) do:[:file|
+ 		file do:[:sq|
+ 		square := self newSquare.
+ 		square borderWidth: 0.
+ 		(sq = 'W' or:[sq = 'B']) ifTrue:[
+ 			square color: (sq = 'W' ifTrue:[white] ifFalse:[black]).
+ 			square borderColor: border.
+ 			square setProperty: #squarePosition toValue: (index := index + 1).
+ 			square setNameTo: 
+ 				(String with: ($a asInteger + (index - 1 bitAnd: 7)) asCharacter with: ($1 asInteger + (index -1 bitShift: -3)) asCharacter).
+ 			square on: #mouseEnter send: #showMoves:from: to: self.
+ 			square on: #mouseEnterDragging send: #dragSquareEnter:from: to: self.
+ 			square on: #mouseLeaveDragging send: #dragSquareLeave:from: to: self.
+ 		] ifFalse:["decoration"
+ 			square color: Color transparent.
+ 			sq = ' ' ifFalse:[
+ 				square addMorph: ((StringMorph contents: sq font: self textFont)
+ 										color: self labelsColor).
+ 			].
+ 		].
+ 		square extent: self squareSize @ self squareSize.
+ 		self addMorphBack: square.
+ 		square submorphs ifNotEmpty: [square submorphs first center: square center]
+ 	]].
+ !

Item was added:
+ ----- Method: Chess960Morph>>blackColor (in category 'theme') -----
+ blackColor
+ 	
+ 	" Color earth paler duller."	
+ 	"^ Color grass duller"
+ 	^ Color r: 0.343 g: 0.576 b: 0.207!

Item was added:
+ ----- Method: Chess960Morph>>buttonColor (in category 'theme') -----
+ buttonColor
+ 
+ "	^ Color lightBlue3 whiter 	"
+ 	^ Color r: 0.667 g: 0.792 b: 0.833!

Item was added:
+ ----- Method: Chess960Morph>>buttonName:action: (in category 'initialize') -----
+ buttonName: aString action: aSymbol
+ 
+ 	^ SimpleButtonMorph new
+ 		target: self;
+ 		label: aString;
+ 		actionSelector: aSymbol;
+ 		color: self buttonColor; 
+ 		borderWidth: 1;
+ 		borderRaised.
+ !

Item was added:
+ ----- Method: Chess960Morph>>defaultBounds (in category 'initialization') -----
+ defaultBounds
+ 	"answer the default bounds for the receiver"
+ 	^ 0 @ 0 corner: (self squareSize * 10 + 10) @ (self squareSize * 10 + 10)!

Item was added:
+ ----- Method: Chess960Morph>>defaultColor (in category 'theme') -----
+ defaultColor
+ 
+ 	"^ Color paleTeal duller duller"
+ 	^ Color r: 0.467 g: 0.631 b: 0.71!

Item was added:
+ ----- Method: Chess960Morph>>findBestMove (in category 'playing') -----
+ findBestMove
+ 	| move |
+ 	board ifNil: [^ self].
+ 	board searchAgent isThinking ifTrue:[^self].
+ 
+ "tmp - board should be nil when the game is over"
+ 	((1 to: 64) allSatisfy: [:n |
+ 		(board activePlayer pieces at: n) isZero
+ 			or: [(board activePlayer findValidMovesAt: n) isEmpty]])
+ 				ifTrue: [message := (board activePlayer isWhitePlayer 
+ 											ifTrue: ['white'] ifFalse: ['black']), ' lost'. 
+ 						^ self].
+ 
+ 	Cursor wait showWhile:[move := board searchAgent think].
+ 	message :=  'I suggest ' translated, move moveString.
+ 	^move
+ !

Item was added:
+ ----- Method: Chess960Morph>>finishedGame: (in category 'as yet unclassified') -----
+ finishedGame: result
+ 
+ 	super finishedGame: result.
+ 	message := #('black won' 'draw' 'white won') at: result * 2 + 1!

Item was added:
+ ----- Method: Chess960Morph>>highColor (in category 'theme') -----
+ highColor
+ 	
+ "	^ Color lightGold"
+ 	^ Color r: 0.992 g: 0.863 b: 0.361!

Item was added:
+ ----- Method: Chess960Morph>>images (in category 'theme') -----
+ images
+ 
+ 	^ images ifNil: [images := ChessPieceMorphWC piecesWithHeight: self squareSize - 5]!

Item was added:
+ ----- Method: Chess960Morph>>initialize (in category 'initialization') -----
+ initialize
+ 	"initialize the state of the receiver"
+ 	super initialize.
+ 	self bounds: self defaultBounds.
+ 	self beSticky!

Item was added:
+ ----- Method: Chess960Morph>>labelsColor (in category 'theme') -----
+ labelsColor
+ 	
+ "	^ Color armyGreen"
+ 	^ Color r: 0.294 g: 0.365 b: 0.086!

Item was added:
+ ----- Method: Chess960Morph>>movedPiece:from:to: (in category 'game callbacks') -----
+ movedPiece: piece from: sourceSquare to: destSquare
+ 	| sourceMorph destMorph sourcePos destPos w startTime nowTime deltaTime |
+ 	sourceMorph := (self atSquare: sourceSquare) firstSubmorph.
+ 	destMorph := self atSquare: destSquare.
+ 	animateMove ifTrue:[
+ 		sourcePos := sourceMorph boundsInWorld center.
+ 		destPos := destMorph boundsInWorld center.
+ 		(w := self world) ifNotNil:[
+ 			w addMorphFront: sourceMorph.
+ 			deltaTime := (sourcePos dist: destPos) * 3 asInteger.
+ 			startTime := Time millisecondClockValue.
+ 			[nowTime := Time millisecondClockValue.
+ 			nowTime - startTime < deltaTime] whileTrue:[
+ 				sourceMorph center: sourcePos + (destPos - sourcePos * (nowTime - startTime) // deltaTime) asIntegerPoint.
+ 				w displayWorldSafely].
+ 			sourceMorph removeDropShadow.
+ 		].
+ 	].
+ 	destMorph removeAllMorphs.
+ 	destMorph addMorphCentered: sourceMorph.
+ 	animateMove := false.
+ 	message := nil.!

Item was added:
+ ----- Method: Chess960Morph>>new960Game (in category 'initialize') -----
+ new960Game
+ 	board := Chess960Board new.
+ 	board initialize.
+ 	board userAgent: self.
+ 	board initializeNewBoard.
+ 	history := OrderedCollection new.
+ 	redoList := OrderedCollection new.
+ 	message := nil
+ !

Item was added:
+ ----- Method: Chess960Morph>>newPiece:white: (in category 'initialize') -----
+ newPiece: piece white: isWhite
+ 
+ 	| index selector m |
+ 	index := piece.
+ 	isWhite ifFalse:[index := index + 6].
+ 	selector := #(	
+ 		whitePawn
+ 		whiteKnight
+ 		whiteBishop
+ 		whiteRook
+ 		whiteQueen
+ 		whiteKing
+ 
+ 		blackPawn
+ 		blackKnight
+ 		blackBishop
+ 		blackRook
+ 		blackQueen
+ 		blackKing) at: index.
+ 	m := ChessPieceMorph new image: (self images at: selector).
+ 	m setProperty: #isWhite toValue: isWhite.
+ 	m setProperty: #piece toValue: piece.
+ 	^m!

Item was added:
+ ----- Method: Chess960Morph>>reinstallPieces (in category 'resizing') -----
+ reinstallPieces
+ 
+ 	board whitePlayer pieces doWithIndex: [:pc :n |
+ 		pc isZero ifFalse: [
+ 			self addedPiece: pc at: n white: true]].
+ 
+ 	board blackPlayer pieces doWithIndex: [:pc :n |
+ 		pc isZero ifFalse: [
+ 			self addedPiece: pc at: n white: false]].!

Item was added:
+ ----- Method: Chess960Morph>>setExtentFromHalo: (in category 'miscellaneous') -----
+ setExtentFromHalo: anExtent
+ 
+ 	self squareSize: (anExtent x - 10) //10.!

Item was added:
+ ----- Method: Chess960Morph>>showMovesAt: (in category 'events') -----
+ showMovesAt: square
+ 	| list |
+ 	board ifNil:[^self].
+ 	board searchAgent isThinking ifTrue:[^self].
+ 	self squaresDo:[:m| m borderWidth: 0].
+ 	list := board activePlayer findValidMovesAt: square.
+ 	list isEmpty ifTrue:[^self].
+ 	(self atSquare: square) borderWidth: 2.
+ 	list do:[:move|
+ 		(self atSquare: (move triggerSquareIn: board)) borderWidth: 5.
+ 	].!

Item was added:
+ ----- Method: Chess960Morph>>squareSize (in category 'resizing') -----
+ squareSize
+ 	
+ 	^ squareSize ifNil: [70]!

Item was added:
+ ----- Method: Chess960Morph>>squareSize: (in category 'resizing') -----
+ squareSize: anInteger
+ 	
+ 	| ss |
+ 
+ 	ss := anInteger max: 48.
+ 
+ 	squareSize := ss.
+ 	images := nil.
+ 	submorphs do: #delete.
+ 	self extent: (ss * 10 + 10) @ (ss * 10 + 10) .
+ 	self addSquares.
+ 	self addButtonRow.	
+ 	self reinstallPieces!

Item was added:
+ ----- Method: Chess960Morph>>statusColor (in category 'theme') -----
+ statusColor
+ 
+ "	^ Color reallyLightBlue 	"
+ 	^ Color r: 0.831 g: 1 b: 1!

Item was added:
+ ----- Method: Chess960Morph>>statusString (in category 'other stuff') -----
+ statusString
+ 
+ 	^ message ifNil: [super statusString]!

Item was added:
+ ----- Method: Chess960Morph>>swappedPieceOn:withPieceOn: (in category 'game callbacks') -----
+ swappedPieceOn: aSquare withPieceOn: bSquare
+ 	| aMorph bMorph |
+ 
+ 	aMorph := (self atSquare: aSquare) firstSubmorph.
+ 	bMorph := (self atSquare: bSquare) firstSubmorph.
+ 
+ 	(self atSquare: aSquare) removeAllMorphs.
+ 	(self atSquare: aSquare) addMorphCentered: bMorph.
+ 
+ 	(self atSquare: bSquare)  removeAllMorphs.
+ 	(self atSquare: bSquare)  addMorphCentered: aMorph.
+ 
+ 	message := nil.!

Item was added:
+ ----- Method: Chess960Morph>>textFont (in category 'theme') -----
+ textFont 
+ 
+ 	| ps |
+ 
+ 	ps := self squareSize < 80 ifTrue: [12] ifFalse: [15].
+ 
+ 	^ TTCFont familyName: 'BitstreamVeraSans' pointSize: ps emphasis: 1
+ !

Item was added:
+ ----- Method: Chess960Morph>>whiteColor (in category 'theme') -----
+ whiteColor
+ 	
+ "	^ Color ivory"
+ 	^ Color r: 1 g: 1 b: 0.94!

Item was added:
+ ChessMoveGenerator subclass: #Chess960MoveGenerator
+ 	instanceVariableNames: ''
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Etoys-Squeakland-Morphic-Games-Chess960'!
+ 
+ !Chess960MoveGenerator commentStamp: 'spfa 6/1/2020 14:56' prior: 0!
+ Chess960MoveGenerator implements the specific castling checks and moves for Chess960!

Item was added:
+ ----- Method: Chess960MoveGenerator>>canCastleBlackKingSide (in category 'support') -----
+ canCastleBlackKingSide
+ 
+ 	(castlingStatus bitAnd: CastlingEnableKingSide) = 0 ifFalse:[^false].
+ 
+ 	(myPlayer rightCastlingField inject: 0 into: [:sum :s| 
+ 			sum + (myPieces at: s) + (itsPieces at: s)]) = (King + Rook)
+ 		ifFalse:[^false].
+ 
+ 	myPlayer rightCastlingWalk in: [:w |
+ 		(self checkRookMoversAttacksAlong: w) ifTrue: [^false].
+ 		(self checkBishopMoversAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkKnightAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkPawnsAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkKingAttacksAlong: w) ifTrue: [^ false]].
+ 
+ 	(self checkAttack: (myPlayer initialKingSquare - 1 to: A8 by: -1) fromPieces: RookMovers)
+ 		ifTrue: [^false].
+ 	(self checkAttack: {H8} fromPieces: RookMovers) ifTrue: [^false].
+ 
+ 	^true.
+ 	
+ 	
+ 	
+ 	
+ 	!

Item was added:
+ ----- Method: Chess960MoveGenerator>>canCastleBlackQueenSide (in category 'support') -----
+ canCastleBlackQueenSide
+ 
+ 	(castlingStatus bitAnd: CastlingEnableQueenSide) = 0 ifFalse:[^false].
+ 
+ 	(myPlayer leftCastlingField inject: 0 into: [:sum :s| 
+ 			sum + (myPieces at: s) + (itsPieces at: s)]) = (King + Rook)
+ 		ifFalse:[^false].
+ 
+ 	myPlayer leftCastlingWalk in: [:w |
+ 		(self checkRookMoversAttacksAlong: w) ifTrue: [^false].
+ 		(self checkBishopMoversAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkKnightAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkPawnsAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkKingAttacksAlong: w) ifTrue: [^ false]].
+ 
+ 	(self checkAttack: (myPlayer initialKingSquare +1 to: H8) fromPieces: RookMovers)
+ 		ifTrue: [^false].
+ 	(self checkAttack: {B8 . A8} fromPieces: RookMovers) ifTrue: [^false].
+ 
+ 
+ 	^true.
+ 	
+ 	
+ 	
+ 	
+ 	!

Item was added:
+ ----- Method: Chess960MoveGenerator>>canCastleWhiteKingSide (in category 'support') -----
+ canCastleWhiteKingSide
+ 
+ 	(castlingStatus bitAnd: CastlingEnableKingSide) = 0 ifFalse:[^false].
+ 
+ 	(myPlayer rightCastlingField inject: 0 into: [:sum :s| 
+ 			sum + (myPieces at: s) + (itsPieces at: s)]) = (King + Rook)
+ 		ifFalse:[^false].
+ 
+ 	myPlayer rightCastlingWalk in: [:w |
+ 		(self checkRookMoversAttacksAlong: w) ifTrue: [^false].
+ 		(self checkBishopMoversAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkKnightAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkPawnsAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkKingAttacksAlong: w) ifTrue: [^ false]].
+ 
+ 	(self checkAttack: (myPlayer initialKingSquare - 1 to: A1 by: -1) fromPieces: RookMovers)
+ 		ifTrue: [^false].
+ 	(self checkAttack: {H1} fromPieces: RookMovers) ifTrue: [^false].
+ 
+ 	^true.
+ 	
+ 	
+ 	
+ 	
+ 	!

Item was added:
+ ----- Method: Chess960MoveGenerator>>canCastleWhiteQueenSide (in category 'support') -----
+ canCastleWhiteQueenSide
+ 
+ 	(castlingStatus bitAnd: CastlingEnableQueenSide) = 0 ifFalse:[^false].
+ 
+ 	(myPlayer leftCastlingField inject: 0 into: [:sum :s| 
+ 			sum + (myPieces at: s) + (itsPieces at: s)]) = (King + Rook)
+ 		ifFalse:[^false].
+ 
+ 	myPlayer leftCastlingWalk in: [:w |
+ 		(self checkRookMoversAttacksAlong: w) ifTrue: [^false].
+ 		(self checkBishopMoversAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkKnightAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkPawnsAttacksAlong: w) ifTrue: [^ false].
+ 		(self checkKingAttacksAlong: w) ifTrue: [^ false]].
+ 
+ 	(self checkAttack: (myPlayer initialKingSquare + 1 to: H1) fromPieces: RookMovers)
+ 		ifTrue: [^false].
+ 	(self checkAttack: {B1 . A1} fromPieces: RookMovers) ifTrue: [^false].
+ 
+ 	^true.
+ 	
+ 	
+ 	
+ 	
+ 	!

Item was added:
+ ----- Method: Chess960MoveGenerator>>checkBishopMoversAttacksAlong: (in category 'support') -----
+ checkBishopMoversAttacksAlong: anArray
+ 
+ 	"anArray contains consecutive, ordered squares that are all either in rank 8 or in rank 1"
+ 	
+ 	anArray do: [:s |
+ 		(self checkBishopMoversAttacksOn: s) ifTrue: [^ true]].
+ 
+ 	^ false!

Item was added:
+ ----- Method: Chess960MoveGenerator>>checkBishopMoversAttacksOn: (in category 'support') -----
+ checkBishopMoversAttacksOn: aSquare
+ 
+ 	"aSquare is either in rank 8 or in rank 1"
+ 	
+ 	| leftDiagonal rightDiagonal |
+ 
+ 	myPlayer isWhitePlayer ifFalse: [
+ 		leftDiagonal := (1 to: aSquare - A8) collect: [:n | aSquare - (n * 7)].
+ 		rightDiagonal := (1 to: H8 - aSquare) collect: [:n | aSquare - (n * 9)]
+ 	]
+ 	ifTrue: [
+ 		leftDiagonal := (1 to: aSquare - A1) collect: [:n | aSquare + (n * 7)].
+ 		rightDiagonal := (1 to: H1 - aSquare) collect: [:n | aSquare + (n * 9)]
+ 	].
+ 
+ 	^ (self checkAttack: leftDiagonal fromPieces: BishopMovers)
+ 		or: [self checkAttack: rightDiagonal fromPieces: BishopMovers]!

Item was added:
+ ----- Method: Chess960MoveGenerator>>checkKingAttacksAlong: (in category 'support') -----
+ checkKingAttacksAlong: anArray
+ 
+ 	"anArray contains consecutive, ordered squares that are all either in rank 8 or in rank 1"
+ 	
+ 	| kpos |
+ 
+ 	"somewhat overkill because some positions can never be reached by opponent king"
+ 	kpos := Array streamContents: [:str |
+ 		str nextPut: anArray first - 1.
+ 		str nextPutAll: anArray.
+ 		str nextPut: anArray last + 1].
+ 
+ 	^ self checkUnprotectedAttack:
+ 			(kpos + (myPlayer isWhitePlayer ifTrue: [8] ifFalse: [-8]))
+ 		fromPiece: King!

Item was added:
+ ----- Method: Chess960MoveGenerator>>checkKnightAttacksAlong: (in category 'support') -----
+ checkKnightAttacksAlong: anArray
+ 
+ 	"anArray contains consecutive, ordered squares that are all either in rank 8 or in rank 1"
+ 	
+ 	| kpos1 kpos2 |
+ 
+ 	"rank at distance 1"
+ 	kpos1 := (anArray - 2) union: (anArray + 2).
+ 
+ 	myPlayer isWhitePlayer ifTrue: [
+ 		kpos1 min = 0 ifTrue: [kpos1 := kpos1 copyWithout: 0].
+ 		kpos1 max = 9 ifTrue: [kpos1 := kpos1 copyWithout: 9]].
+ 
+ 	(self checkUnprotectedAttack:
+ 			(kpos1 + (myPlayer isWhitePlayer ifTrue: [8] ifFalse: [-8]))
+ 		fromPiece: Knight) ifTrue: [^ true].
+ 
+ 	"rank at distance 2 - same logic as for pawns at distance 1"
+ 	kpos2 := Array streamContents: [:str |
+ 		str nextPut: anArray min - 1.
+ 		anArray size > 1 ifTrue: [str nextPutAll: anArray].
+ 		str nextPut: anArray max + 1].
+ 
+ 	^ self checkUnprotectedAttack:
+ 			(kpos2 + (myPlayer isWhitePlayer ifTrue: [16] ifFalse: [-16]))
+ 		fromPiece: Knight!

Item was added:
+ ----- Method: Chess960MoveGenerator>>checkPawnsAttacksAlong: (in category 'support') -----
+ checkPawnsAttacksAlong: anArray
+ 
+ 	"anArray contains consecutive, ordered squares that are all either in rank 8 or in rank 1"
+ 	
+ 	| ppos |
+ 
+ 	ppos := Array streamContents: [:str |
+ 		str nextPut: anArray first - 1.
+ 		"If the king does not move, castling is not prevented by a pawn in same file"
+ 		anArray size > 1 ifTrue: [str nextPutAll: anArray].
+ 		str nextPut: anArray last + 1].
+ 
+ 	^ self checkUnprotectedAttack:
+ 			(ppos + (myPlayer isWhitePlayer ifTrue: [8] ifFalse: [-8]))
+ 		fromPiece: Pawn!

Item was added:
+ ----- Method: Chess960MoveGenerator>>checkRookMoversAttacksAlong: (in category 'support') -----
+ checkRookMoversAttacksAlong: anArray
+ 
+ 	"anArray contains consecutive, ordered squares that are all either in rank 8 or in rank 1"
+ 	
+ 	anArray first > 8 ifTrue: [ "black"
+ 		anArray do: [:s |
+ 			(self checkAttack: {s-8. s-16. s-24. s-32. s-40. s-48. s-56} fromPieces: RookMovers)
+ 				ifTrue: [^ true]].
+ 		^ false].
+ 
+ 	"white"
+ 	anArray do: [:s |
+ 		(self checkAttack: {s+8. s+16. s+24. s+32. s+40. s+48. s+56} fromPieces: RookMovers)
+ 			ifTrue: [^ true]].
+ 	^ false
+ 	!

Item was added:
+ ----- Method: Chess960MoveGenerator>>moveBlackKingAt: (in category 'moves-general') -----
+ moveBlackKingAt: square
+ 	| capture |
+ 	(KingMoves at: square) do:[:destSquare|
+ 		(myPieces at: destSquare) = 0 ifTrue:[
+ 			capture := itsPieces at: destSquare.
+ 			(forceCaptures and:[capture = 0]) ifFalse:[
+ 				(moveList at: (lastMoveIndex := lastMoveIndex + 1))
+ 					move: King from: square to: destSquare capture: capture.
+ 				capture = King ifTrue:[kingAttack := moveList at: lastMoveIndex].
+ 			].
+ 		].
+ 	].
+ 	forceCaptures ifTrue:[^self].
+ 	"now consider castling"
+ 	self canCastleBlackKingSide ifTrue:[
+ 		(moveList at: (lastMoveIndex := lastMoveIndex + 1))
+ 			moveCastlingKingSide: King from: square to: G8
+ 	].
+ 	self canCastleBlackQueenSide ifTrue:[
+ 		(moveList at: (lastMoveIndex := lastMoveIndex + 1))
+ 			moveCastlingQueenSide: King from: square to: C8
+ 	].!

Item was added:
+ ----- Method: Chess960MoveGenerator>>moveWhiteKingAt: (in category 'moves-general') -----
+ moveWhiteKingAt: square
+ 	| capture |
+ 	(KingMoves at: square) do:[:destSquare|
+ 		(myPieces at: destSquare) = 0 ifTrue:[
+ 			capture := itsPieces at: destSquare.
+ 			(forceCaptures and:[capture = 0]) ifFalse:[
+ 				(moveList at: (lastMoveIndex := lastMoveIndex + 1))
+ 					move: King from: square to: destSquare capture: capture.
+ 				capture = King ifTrue:[kingAttack := moveList at: lastMoveIndex].
+ 			].
+ 		].
+ 	].
+ 	forceCaptures ifTrue:[^self].
+ 	"now consider castling"
+ 	self canCastleWhiteKingSide ifTrue:[
+ 		(moveList at: (lastMoveIndex := lastMoveIndex + 1))
+ 			moveCastlingKingSide: King from: square to: G1.
+ 	].
+ 	self canCastleWhiteQueenSide ifTrue:[
+ 		(moveList at: (lastMoveIndex := lastMoveIndex + 1))
+ 			moveCastlingQueenSide: King from: square to: C1.
+ 	].!

Item was added:
+ ChessPlayer subclass: #Chess960Player
+ 	instanceVariableNames: 'configuration'
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Etoys-Squeakland-Morphic-Games-Chess960'!
+ 
+ !Chess960Player commentStamp: 'spfa 6/2/2020 15:16' prior: 0!
+ Chess960Player represents a Chess960 player (doh)!

Item was added:
+ ----- Method: Chess960Player>>addBlackPieces: (in category 'adding/removing') -----
+ addBlackPieces: aChess960Configuration
+ 
+ 	self configuration: aChess960Configuration.
+ 
+ 	configuration positions doWithIndex: [:p :n | self addPiece: p at: 56+n].
+ 	49 to: 56 do:[:i| self addPiece: Pawn at: i].!

Item was added:
+ ----- Method: Chess960Player>>addWhitePieces: (in category 'adding/removing') -----
+ addWhitePieces: aChess960Configuration
+ 
+ 	self configuration: aChess960Configuration.
+ 
+ 	configuration positions doWithIndex: [:p :n | self addPiece: p at: n].
+ 	9 to: 16 do:[:i| self addPiece: Pawn at: i].
+ !

Item was added:
+ ----- Method: Chess960Player>>applyCastleKingSideMove: (in category 'moving') -----
+ applyCastleKingSideMove: move
+ 
+ 	(pieces at: move destinationSquare) isZero "rook" ifFalse: [
+ 		castlingRookSquare := self isWhitePlayer ifTrue: [F1] ifFalse: [F8].
+ 		move sourceSquare = castlingRookSquare 
+ 			ifTrue: [
+ 				self swapPiecesIn: move sourceSquare and: move destinationSquare]
+ 			ifFalse: [
+ 				self movePiece: Rook from: self initialRightRookSquare to: castlingRookSquare.
+ 				self movePiece: King from: move sourceSquare to: move destinationSquare].
+ 		castlingStatus := castlingStatus bitOr: CastlingDone.
+ 		^ self].
+ 
+ 	self movePiece: move movingPiece from: move sourceSquare to: move destinationSquare.
+ 	self movePiece: Rook 
+ 		from: self initialRightRookSquare 
+ 		to: ((castlingRookSquare := self isWhitePlayer ifTrue: [F1] ifFalse: [F8])).
+ 	pieces at: castlingRookSquare put: King.
+ 	castlingStatus := castlingStatus bitOr: CastlingDone.!

Item was added:
+ ----- Method: Chess960Player>>applyCastleQueenSideMove: (in category 'moving') -----
+ applyCastleQueenSideMove: move
+ 
+ 	(pieces at: move destinationSquare) isZero "rook or king" ifFalse: [
+ 		castlingRookSquare := self isWhitePlayer ifTrue: [D1] ifFalse: [D8].
+ 		move sourceSquare = castlingRookSquare 
+ 			ifTrue: [
+ 				self swapPiecesIn: move sourceSquare and: move destinationSquare]
+ 			ifFalse: [
+ 				self movePiece: Rook 
+ 					from: self initialLeftRookSquare to: castlingRookSquare.
+ 				self movePiece: King from: move sourceSquare to: move destinationSquare].
+ 		castlingStatus := castlingStatus bitOr: CastlingDone.
+ 		^ self].
+ 
+ 	self movePiece: move movingPiece from: move sourceSquare to: move destinationSquare.
+ 	self movePiece: Rook 
+ 		from: self initialLeftRookSquare 
+ 		to: (castlingRookSquare := self isWhitePlayer ifTrue: [D1] ifFalse: [D8]).
+ 	pieces at: castlingRookSquare put: King.
+ 	castlingStatus := castlingStatus bitOr: CastlingDone.!

Item was added:
+ ----- Method: Chess960Player>>configuration (in category 'configuration') -----
+ configuration
+ 
+ 	^ configuration!

Item was added:
+ ----- Method: Chess960Player>>configuration: (in category 'configuration') -----
+ configuration: aChess960Configuration
+ 
+ 	configuration := aChess960Configuration!

Item was added:
+ ----- Method: Chess960Player>>copyPlayer: (in category 'copying') -----
+ copyPlayer: aPlayer
+ 
+ 	super copyPlayer: aPlayer.
+ 	configuration := aPlayer configuration!

Item was added:
+ ----- Method: Chess960Player>>initialKingSquare (in category 'configuration') -----
+ initialKingSquare
+ 
+ 	^ self isWhitePlayer ifTrue: [self configuration initialKingPosition] 
+ 		ifFalse: [self configuration initialKingPosition + 56]!

Item was added:
+ ----- Method: Chess960Player>>initialLeftRookSquare (in category 'configuration') -----
+ initialLeftRookSquare
+ 
+ 	^ self isWhitePlayer ifTrue: [self configuration initialLeftRookPosition] 
+ 		ifFalse: [self configuration initialLeftRookPosition + 56]!

Item was added:
+ ----- Method: Chess960Player>>initialRightRookSquare (in category 'configuration') -----
+ initialRightRookSquare
+ 
+ 	^ self isWhitePlayer ifTrue: [self configuration initialRightRookPosition] 
+ 		ifFalse: [self configuration initialRightRookPosition + 56]!

Item was added:
+ ----- Method: Chess960Player>>leftCastlingField (in category 'configuration') -----
+ leftCastlingField
+ 
+ 	"The squares walked by both the king and the left rook when castling to the left - they must  be clear of other pieces"
+ 
+ 	^ self isWhitePlayer 
+ 		ifTrue: [(C1 to: self initialKingSquare) union: (self initialLeftRookSquare to: D1)] 
+ 		ifFalse: [(C8 to: self initialKingSquare) union: (self initialLeftRookSquare to: D8)]
+ !

Item was added:
+ ----- Method: Chess960Player>>leftCastlingWalk (in category 'configuration') -----
+ leftCastlingWalk
+ 
+ 	"The squares walked by the king when castling to the left - they must not be under check"
+ 
+ 	| ks |
+ 
+ 	ks := self initialKingSquare.
+ 	
+ 	^ self isWhitePlayer 
+ 		ifTrue: [ks > C1 ifTrue: [C1 to: ks] ifFalse: [ks to: C1]] 
+ 		ifFalse: [ks > C8 ifTrue: [C8 to: ks] ifFalse: [ks to: C8]] !

Item was added:
+ ----- Method: Chess960Player>>movePiece:from:to: (in category 'adding/removing') -----
+ movePiece: piece from: sourceSquare to: destSquare
+ 
+ 	sourceSquare = destSquare ifTrue: [^ self].
+ 	super movePiece: piece from: sourceSquare to: destSquare!

Item was added:
+ ----- Method: Chess960Player>>rightCastlingField (in category 'configuration') -----
+ rightCastlingField
+ 
+ 	"The squares walked by both the king and the right rook when castling to the left - they must  be clear of other pieces"
+ 
+ 	^ self isWhitePlayer 
+ 		ifTrue: [(self initialKingSquare to: G1) union: (F1 to: self initialRightRookSquare)] 
+ 		ifFalse: [(self initialKingSquare to: G8) union: (F8 to: self initialRightRookSquare)]!

Item was added:
+ ----- Method: Chess960Player>>rightCastlingWalk (in category 'configuration') -----
+ rightCastlingWalk
+ 
+ 	"The squares walked by the king when castling to the right - they must not be under check"
+ 
+ 	| ks |
+ 
+ 	ks := self initialKingSquare.
+ 	
+ 	^ self isWhitePlayer 
+ 		ifTrue: [ks > G1 ifTrue: [G1 to: ks] ifFalse: [ks to: G1]] 
+ 		ifFalse: [ks > G8 ifTrue: [G8 to: ks] ifFalse: [ks to: G8]] !

Item was added:
+ ----- Method: Chess960Player>>swapPiecesIn:and: (in category 'adding/removing') -----
+ swapPiecesIn: aSquare and: bSquare
+ 
+ 	"Only applies to specific castling moves"
+ 
+ 	| score pa pb |
+ 
+ 	pa := pieces at: aSquare.
+ 	pb := pieces at: bSquare.
+ 	
+ 	score := PieceCenterScores at: pa.
+ 	positionalValue := positionalValue - (score at: aSquare).
+ 	positionalValue := positionalValue + (score at: bSquare).
+ 
+ 	score := PieceCenterScores at: pb.
+ 	positionalValue := positionalValue - (score at: bSquare).
+ 	positionalValue := positionalValue + (score at: aSquare).
+ 
+ 	pieces at: aSquare put: pb.
+ 	pieces at: bSquare put: pa.
+ 	board updateHash: pa at: aSquare from: self.
+ 	board updateHash: pa at: bSquare from: self.
+ 	board updateHash: pb at: bSquare from: self.
+ 	board updateHash: pb at: aSquare from: self.
+ 
+ 	self userAgent ifNotNil:[self userAgent swappedPieceOn: aSquare withPieceOn: bSquare].!

Item was added:
+ ----- Method: Chess960Player>>undoCastleKingSideMove: (in category 'undo') -----
+ undoCastleKingSideMove: move
+ 	self prepareNextMove. "in other words, remove extra kings"
+ 	self movePiece: move movingPiece from: move destinationSquare to: move sourceSquare.
+ 
+ 	self isWhitePlayer ifTrue: [
+ 			self movePiece: Rook from: F1 to: self initialRightRookPosition.
+ 		] ifFalse: [
+ 			self movePiece: Rook from: F8 to: self initialRightRookPosition + 56.
+ 		]
+ 
+ !

Item was added:
+ ----- Method: Chess960Player>>undoCastleQueenSideMove: (in category 'undo') -----
+ undoCastleQueenSideMove: move
+ 	self prepareNextMove. "in other words, remove extra kings"
+ 	self movePiece: move movingPiece from: move destinationSquare to: move sourceSquare.
+ 
+ 	self isWhitePlayer ifTrue: [
+ 			self movePiece: Rook from: D1 to: self initialLeftRookPosition.
+ 		] ifFalse: [
+ 			self movePiece: Rook from: D8 to: self initialLeftRookPosition + 56.
+ 		]
+ 
+ !

Item was added:
+ ----- Method: Chess960Player>>updateCastlingStatus: (in category 'moving') -----
+ updateCastlingStatus: move
+ 
+ 	"Cannot castle when king has moved"
+ 	(move movingPiece = King) 
+ 		ifTrue:[^castlingStatus := castlingStatus bitOr: CastlingDisableAll].
+ 
+ 	"See if a rook has moved"
+ 	(move movingPiece = Rook) ifFalse:[^self].
+ 
+ 	(move sourceSquare = self initialLeftRookSquare) 
+ 			ifTrue:[^castlingStatus := castlingStatus bitOr: CastlingDisableQueenSide].
+ 
+ 	(move sourceSquare = self initialRightRookSquare) 
+ 			ifTrue:[^castlingStatus := castlingStatus bitOr: CastlingDisableKingSide].!

Item was changed:
  ----- Method: ChessBoard>>movePieceFrom:to: (in category 'moving') -----
  movePieceFrom: sourceSquare to: destSquare
  	| move |
  	searchAgent isThinking ifTrue:[^self].
  	move := (activePlayer findPossibleMovesAt: sourceSquare) contents
+ 		detect:[:any| any destinationSquare = destSquare
+ 						or: [(any triggerSquareIn: self) = destSquare]].
- 		detect:[:any| any destinationSquare = destSquare].
  	self nextMove: move.
  	searchAgent activePlayer: activePlayer.!

Item was changed:
  ----- Method: ChessMorph>>showMovesAt: (in category 'events') -----
  showMovesAt: square
  	| list |
  	board ifNil:[^self].
  	board searchAgent isThinking ifTrue:[^self].
  	self squaresDo:[:m| m borderWidth: 0].
  	list := board activePlayer findValidMovesAt: square.
  	list isEmpty ifTrue:[^self].
  	(self atSquare: square) borderWidth: 1.
  	list do:[:move|
+ 		(self atSquare: (move triggerSquareIn: board)) borderWidth: 1.
- 		(self atSquare: move destinationSquare) borderWidth: 1.
  	].!

Item was added:
+ ----- Method: ChessMove>>triggerSquareIn: (in category 'accessing') -----
+ triggerSquareIn: aChessBoard
+ 
+ 	type = MoveCastlingKingSide ifTrue: [^ aChessBoard activePlayer initialRightRookSquare].
+ 	type = MoveCastlingQueenSide ifTrue: [^ aChessBoard activePlayer initialLeftRookSquare].
+ 
+ 	^destinationSquare!

Item was changed:
  ----- Method: ChessMoveGenerator>>canCastleBlackKingSide (in category 'support') -----
  canCastleBlackKingSide
  	(castlingStatus bitAnd: CastlingEnableKingSide) = 0 ifFalse:[^false].
  	"Quickly check if all the squares are zero"
  	((myPieces at: G8) + (myPieces at: F8) + (itsPieces at: G8) + (itsPieces at: F8) = 0) ifFalse:[^false].
  	"Check for castling squares under attack..  See canCastleBlackQueenSide for details"
- 	(self checkAttack:{H7. H6. H5. H4. H3. H2. H1} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{G7. G6. G5. G4. G3. G2. G1} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{F7. F6. F5. F4. F3. F2. F1} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{E7. E6. E5. E4. E3. E2. E1.} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{D8. C8. B8. A8} fromPieces:RookMovers) ifTrue:[^false].
- 	(self checkAttack:{G7. F6. E5. D4. C3. B2. A1} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{F7. E6. D5. C4. B3. A2} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{E7. D6. C5. B4. A3} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{D7. C6. B5. A4} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{F7. G6. H5} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{G7. H6} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{H7} fromPieces:BishopMovers) ifTrue:[^false].
+ 	(self checkUnprotectedAttack:{H7. G7. E7. D7. C7. H6. G6. F6. E6. D6} fromPiece:Knight) ifTrue:[^false].
- 	(self checkUnprotectedAttack:{H7. G7. F7. E7. D7. C7. H6. G6. F6. E6. D6} fromPiece:Knight) ifTrue:[^false].
  	(self checkUnprotectedAttack:{H7. G7. F7. E7. D7} fromPiece:Pawn) ifTrue:[^false].
+ 	(self checkUnprotectedAttack:{G7} fromPiece:King) ifTrue:[^false].
+ 
  	^true.
  	
  	
  	
  	
  	!

Item was changed:
  ----- Method: ChessMoveGenerator>>canCastleBlackQueenSide (in category 'support') -----
  canCastleBlackQueenSide
  	(castlingStatus bitAnd: CastlingEnableQueenSide) = 0 ifFalse:[^false].
  	"Quickly check if all the squares are zero"
  	((myPieces at: B8) +  (myPieces at: C8) +  (myPieces at: D8) +
  		(itsPieces at: B8) + (itsPieces at: C8) + (itsPieces at: D8) 
  			= 0) ifFalse:[^false].
  	"Check to see if any of the squares involved in castling are under attack.  First
  	check for vertical (rook-like) attacks"
- 	(self checkAttack:{A7. A6. A5. A4. A3. A2. A1} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{B7. B6. B5. B4. B3. B2. B1} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{C7. C6. C5. C4. C3. C2. C1} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{D7. D6. D5. D4. D3. D2. D1} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{E7. E6. E5. E4. E3. E2. E1} fromPieces:RookMovers) ifTrue:[^false].
  	"Check for a rook attack from the baseline"
  	(self checkAttack:{F8. G8. H8} fromPieces:RookMovers) ifTrue:[^false].
  	"Check for bishop attacks from the diagonals"
- 	(self checkAttack:{B7. C6. D5. E4. F3. G2. H1} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{C7. D6. E5. F4. G3. H2} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{D7. E6. F5. G4. H3} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{E7. F6. G5. H4} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{F7. G6. H5} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{A7} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{B7. A6} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{C7. B6. A5} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{D7. C6. B5. A4} fromPieces:BishopMovers) ifTrue:[^false].
  	"Check for a knight attack"
  	(self checkUnprotectedAttack:{A7. B7. C7. D7. E7. F7. G7. A6. B6. C6. D6. E6. F6} fromPiece:Knight) ifTrue:[^false].
  	"check for a pawn attack"
  	(self checkUnprotectedAttack:{A7. B7. C7. D7. E7. F7} fromPiece:Pawn) ifTrue:[^false].
  	"check for a king attack"
  	(self checkUnprotectedAttack:{B7. C7. } fromPiece:King) ifTrue:[^false].
  	^true.
  !

Item was changed:
  ----- Method: ChessMoveGenerator>>canCastleWhiteKingSide (in category 'support') -----
  canCastleWhiteKingSide
  	(castlingStatus bitAnd: CastlingEnableKingSide) = 0 ifFalse: [^false].
  	"Quickly check if all the squares are zero"
  	((myPieces at:G1) + (myPieces at:F1) + (itsPieces at:G1) + (itsPieces at:F1) = 0) ifFalse:[^false].
  	"Check for castling squares under attack..  See canCastleBlackQueenSide for details"
- 	(self checkAttack:{H2. H3. H4. H5. H6. H7. H8} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{G2. G3. G4. G5. G6. G7. G8} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{F2. F3. F4. F5. F6. F7. F8} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{E2. E3. E4. E5. E6. E7. E8} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{A1. A2. A3. A4} fromPieces:RookMovers) ifTrue:[^false].
- 	(self checkAttack:{G2. F3. E4. D5. C6. B7. A8} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{F2. E3. D4. C5. B6. A7} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{E2. D3. C4. B5. A6} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{D2. C3. B4. A5} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{F2. G3. H4} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{G2. H3} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{H2} fromPieces:BishopMovers) ifTrue:[^false].
+ 	(self checkUnprotectedAttack:{H2. G2. E2. D2. C2. H3. G3. F3. E3. D3} fromPiece:Knight) ifTrue:[^false].
- 	(self checkUnprotectedAttack:{H2. G2. F2. E2. D2. C2. H3. G3. F3. E3. D3} fromPiece:Knight) ifTrue:[^false].
  	(self checkUnprotectedAttack:{H2. G2. F2. E2. D2} fromPiece:Pawn) ifTrue:[^false].
  	(self checkUnprotectedAttack:{G2} fromPiece:King) ifTrue:[^false].
  	^true.!

Item was changed:
  ----- Method: ChessMoveGenerator>>canCastleWhiteQueenSide (in category 'support') -----
  canCastleWhiteQueenSide
  	(castlingStatus bitAnd: CastlingEnableQueenSide) = 0 ifFalse: [^false].
  	"Quickly check if all the squares are zero"
  	((myPieces at:B1) + (myPieces at:C1) + (myPieces at:D1) +
  	 (itsPieces at:B1) + (itsPieces at:C1) + (itsPieces at:D1) = 0) ifFalse:[^false].
  	"Check for castling squares under attack..  See canCastleBlackQueenSide for details"
- 	(self checkAttack:{A2. A3. A4. A5. A6. A7. A8} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{B2. B3. B4. B5. B6. B7. B8} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{C2. C3. C4. C5. C6. C7. C8} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{D2. D3. D4. D5. D6. D7. D8} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{E2. E3. E4. E5. E6. E7. E8} fromPieces:RookMovers) ifTrue:[^false].
  	(self checkAttack:{F1. G1. H1} fromPieces:RookMovers) ifTrue:[^false].
- 	(self checkAttack:{B2. C3. D4. E5. F6. G7. H8} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{C2. D3. E4. F5. G6. H7} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{D2. E3. F4. G5. H6} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{E2. F3. G4. H5} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{F2. G3. H4} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{A2} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{B2. A3} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{C2. B3. A4} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkAttack:{D2. C3. B4. A5} fromPieces:BishopMovers) ifTrue:[^false].
  	(self checkUnprotectedAttack:{A2. B2. C2. D2. E2. F2. G2. A3. B3. C3. D3. E3. F3} fromPiece:Knight) ifTrue:[^false].
  	(self checkUnprotectedAttack:{A2. B2. C2. D2. E2. F2} fromPiece:Pawn) ifTrue:[^false].
  	(self checkUnprotectedAttack:{B2. C2} fromPiece:King) ifTrue:[^false].
  	^true.!

Item was added:
+ ChessPieceMorph subclass: #ChessPieceMorphWC
+ 	instanceVariableNames: ''
+ 	classVariableNames: ''
+ 	poolDictionaries: ''
+ 	category: 'Etoys-Squeakland-Morphic-Games-Chess960'!
+ 
+ !ChessPieceMorphWC commentStamp: 'spfa 5/31/2020 10:36' prior: 0!
+ ChessPieceMorphWC class side provides scalable images from Wikimedia Commons!

Item was added:
+ ----- Method: ChessPieceMorphWC class>>pieceExtent (in category 'forms library') -----
+ pieceExtent
+ 
+ 	^ 314 @ 302!

Item was added:
+ ----- Method: ChessPieceMorphWC class>>pieces (in category 'forms library') -----
(excessive size, no diff calculated)

Item was added:
+ ----- Method: ChessPieceMorphWC class>>piecesWithExtent: (in category 'forms library') -----
+ piecesWithExtent: aPoint
+ 
+ 	| form dict ng og pg i ib iw |
+ 
+ 	form := self pieces.
+ 	dict := Dictionary new.
+ 	ng := #( whiteKing  blackKing whiteQueen blackQueen whiteBishop blackBishop whiteKnight  blackKnight whiteRook blackRook whitePawn blackPawn).
+ 
+ 	og := #(55 55 10 10 0 0 0 0 0 0 0 0).
+ 	pg := #(0 0 0 0 20 20 50 50 90 90 120 120).
+ 
+ 	i := 0.
+ 	0 to: 5 do: [:n |
+ 		ib := (i := i + 1) * 2 - 1.
+ 		iw := i * 2.
+ 		dict at: (ng at: ib)
+ 			put: ((form contentsOfArea: (315 * n + (pg at: ib) @0 
+ 											corner: 315 * n + 314 - (og at: ib) @ 302))
+ 					 scaledToSize: aPoint).
+ 		dict at: (ng at: iw)
+ 			put: ((form contentsOfArea: (315 * n + (pg at: iw) @327 
+ 											corner: 315 * n + 314 - (og at: iw) @ 629))
+ 					scaledToSize: aPoint)].
+ 
+ 	^ dict!

Item was added:
+ ----- Method: ChessPieceMorphWC class>>piecesWithHeight: (in category 'forms library') -----
+ piecesWithHeight: anInteger
+ 
+ 	^ self piecesWithExtent: self pieceExtent x * anInteger / self pieceExtent y @ anInteger!

Item was changed:
  ----- Method: ChessPlayer>>applyEnpassantMove: (in category 'moving') -----
  applyEnpassantMove: move
+ 	| capturedSquare |
+ 	capturedSquare := move destinationSquare - (self isWhitePlayer ifTrue:[8] ifFalse:[-8]).
+ 	opponent removePiece: move capturedPiece at: capturedSquare.
+ 	self userAgent ifNotNil:[(self userAgent atSquare: capturedSquare) removeAllMorphs].
- 	opponent removePiece: move capturedPiece at: move destinationSquare - 
- 		(self isWhitePlayer ifTrue:[8] ifFalse:[-8]).
  	^self movePiece: move movingPiece from: move sourceSquare to: move destinationSquare!

Item was changed:
  ----- Method: ChessPlayer>>evaluateMaterial (in category 'evaluation') -----
  evaluateMaterial
  	"Compute the board's material balance, from the point of view of the side
  	player.  This is an exact clone of the eval function in CHESS 4.5"
+ 	| total diff value pawns |
- 	| total diff value |
  	self materialValue = opponent materialValue ifTrue:[^0]. "both sides are equal"
  	total := self materialValue + opponent materialValue.
  	diff := self materialValue - opponent materialValue.
+ 
+ 	pawns := numPawns.
+ 	pawns < 0 ifTrue: ["happens - a bug somewhere" pawns := 0].
+ 
  	value := (2400 min: diff) + 
+ 		((diff * (12000 - total) * pawns) // (6400 * (pawns + 1))).
- 		((diff * (12000 - total) * self numPawns) // (6400 * (self numPawns + 1))).
  	^value!

Item was added:
+ ----- Method: ChessPlayer>>initialLeftRookSquare (in category 'configuration') -----
+ initialLeftRookSquare
+ 
+ 	^ self isWhitePlayer ifTrue: [A1] ifFalse: [A8]!

Item was added:
+ ----- Method: ChessPlayer>>initialRightRookSquare (in category 'configuration') -----
+ initialRightRookSquare
+ 
+ 	^ self isWhitePlayer ifTrue: [H1] ifFalse: [H8]!

Item was changed:
  ----- Method: ChessPlayer>>isValidMoveFrom:to: (in category 'testing') -----
  isValidMoveFrom: sourceSquare to: destSquare
  	| move |
  	move := (self findValidMovesAt: sourceSquare)
+ 			detect:[:any| (any triggerSquareIn: board) = destSquare] ifNone:[nil].
- 			detect:[:any| any destinationSquare = destSquare] ifNone:[nil].
  	^move notNil!

Item was changed:
  ----- Method: ChessPlayer>>removePiece:at: (in category 'adding/removing') -----
  removePiece: piece at: square
+ 
+ 	(pieces at: square) = piece ifFalse: ["fix"
+ 		"Happens at time - some moves have a capturedPiece absent from the board"
+ 		^self].
+ 
  	pieces at: square put: 0.
  	materialValue := materialValue - (PieceValues at: piece).
  	positionalValue := positionalValue - ((PieceCenterScores at: piece) at: square).
  	piece = Pawn ifTrue:[numPawns := numPawns - 1].
  	board updateHash: piece at: square from: self.
+ 	self userAgent ifNotNil:[self userAgent removedPiece: piece at: square].
+ !
- 	self userAgent ifNotNil:[self userAgent removedPiece: piece at: square].!

Item was changed:
  ----- Method: ChessPlayerAI>>statusString (in category 'accessing') -----
  statusString
  	| av count |
  	^String streamContents:[:s|
  		(myMove == #none or:[myMove == nil]) ifFalse:[
+ 			s print: myMove value / 100.0; space.
- 			s print: myMove value * 0.01; space.
  		].
  		av := bestVariation.
  		count := av at: 1.
  		count > 0 ifFalse:[
  			av := activeVariation.
  			count := av at: 1].
  		count > 0 ifFalse:[
  			s nextPutAll:'***'.
  			av := variations at: 1.
  			count := av at: 1.
  			count > 3 ifTrue:[count := 3]].
  		2 to: count + 1 do:[:index|
  			s nextPutAll: (ChessMove decodeFrom: (av at: index)) moveString.
  			s space].
  
  		s nextPut:$[.
  		s print: nodesVisited.
  "		s nextPut:$|.
  		s print: ttHits.
  		s nextPut: $|.
  		s print: alphaBetaCuts.
  "		s nextPut:$].
  
  	].!



More information about the Squeak-dev mailing list