{ Analytica Model Chess_with_GPT, encoding="UTF-8" }
SoftwareVersion 6.3.6
{ System Variables with non-default values: }
SampleSize := 1000
TypeChecking := 1
Checking := 1
SaveOptions := 2
SaveValues := 0
DisplayInputs Object: Object Self, Object Function, Object Index, Object Constant, Keyword Self, Index Param_rec, Index Parameters_rec, Function Enum_vals_for_fn_par, Constant RE_for_Parameters_in, Function Embedding_similarity, Function Embedding_for
DisplayOutputs Object: Object Self, Object Function, Keyword Self
DisplayInputs Function: Object Object, Object Keyword, Object Index, Object Constant, Keyword Self, Index Param_rec, Index Parameters_rec, Function Enum_vals_for_fn_par, Constant RE_for_Parameters_in
DisplayOutputs Function: Object Object, Object Keyword, Object Variable, Keyword Self
DisplayOutputs Keyword: Object Function
DisplayInputs Keyword: Object Function
{!-50299|DiagramColor Model: 65535,65535,65535}
{!-50299|DiagramColor Module: 65535,65535,65535}
{!-50299|DiagramColor LinkModule: 65535,65535,65535}
{!-50299|DiagramColor Library: 65535,65535,65535}
{!-50299|DiagramColor LinkLibrary: 65535,65535,65535}
{!-50299|DiagramColor Form: 65535,65535,65535}
DisplayInputs Variable: Object Function, Function Embedding_similarity, Function Embedding_for
DisplayOutputs Index: Object Object, Object Function
DisplayOutputs Constant: Object Object, Object Function
NodeInfo FormNode: 1,0,0,,0,0,,,,0,,,0
{!-50299|NodeColor Text: 62258,62258,62258}
{!-60000|Attribute AcpStyles}
Model Chess_with_GPT
Author: Lonnie Chrisman~
Lumina Decision Systems
Date: Wed, Sep 27, 2023 8:25 AM
DiagState: 2,0,0,1474,658,17,10
FontStyle: Arial,15
FileInfo: 0,Model Chess_with_GPT,2,2,0,0,C:\Temp\Chess with GPT.ana
Picture Boardimage
NodeLocation: 312,332,-2
NodeSize: 256,260
WindState: 2,343,21,986,906
Pict: (000000000000020002000004DC50000089504E470D0A1A0A0000000D4948445200000200000002000806000000F478D4FA000000017352474200AECE1CE90000000467414D410000B18F0BFC6105000000097048597300000EC300000EC301C76FA8640000506149444154785EED9DBFAB1DC7FDFED5BB50630C6E041F77AE0C766977B25B17EADDDCCA950B814A810B05372A83E42A11FEBA0BAA6208C2180282E81F1038851A853469D427CD7E6776777667679F3D3FF6CC7BEF3DE7FD2A5E443ABFE4F33C33CF3C33BBF7E6D6FFFEF94B03000000BE180AC07F7FFFAB5BFEF3F73F37BFFFFC07B7BCFBC7CF52172FE03FFE2B5DBC80FF7EFD6F0B40142115018FFCFEFF1E357FF9F2FFDCF29FBFFF49EAE205FCC77FA58B17F0DFAFFF148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C5031480C0B603E04EF3EDFBB79AAF3FEBFEFEF4E3DBCDB79F97AFD9160260EB00F8B0F9FAD6ADE6D6C0EDE67BF9BA6DC07F0A80D2C5863F353F7E71ABB9FF53F7F7378FEE353FFE56BE665B28001400298E0D5D01E8423F2D04EF5D6B09D82200DE3CFAB45FECEE35BFE6CFFDF65DF355BF107EF5E87A16A2AD03E0FB3BDDF71D16FECF3F683EB9F3A17CED166CB700FCD0DCEFBDD614636323B6F0FFE9C7EFF5DFB1287BD1FBFEFB7FF2F19DC97BB6E23A0A40E7751A0F9F5E6B09A0006C5900B2C09F727D8360D301904D78C9FB1F344FD5FB0CB10F8069F0A7F6DFF2D3BDECFB5FCF18B89E0258700DBE27AEA3007C7575AFCF814F9BFB570BE57023ECFD9F9EF8A4D3BF96CF6E0F8F5FD74660D302B098FF3D5F7CD7BC51EF33E466E4FFF5786F5800F2D0CF827D12F8538685211F241B0C882D07C0B8135862FB81601E0085E7939DFEAEE736A2A6FFA5BF93B06F39A2004C1607BB1DE2D60560F038783F1E05C71270A10560978F1B79BC8B2D0BC07812B8C4F69B001BFFF3D297657AE177CE9015794930DE18542F00DAE0130A4086D5E2B05D015808FF1DCC1790FA6C5D006E5DFDB0F8DCE4746023EAF99F267D3AE68D7F9F5FDF572570EE73786F9AFC4320D894C3AD0BC0CCE7610CF82800B7F2CB3DC5735BCCF792EDFC4FC7FF87B3451ED4F45F6FF04E28001916E5B06A01586E77750A40C4A2046C5500C66BBFBB8883656C8F5BEC08CC0360E6E7381E2663E61A8EFF22D5FC9713572FDA7950488F65505C4E01C84BE0AF57E9FB5D6801988D8BD1C7C982714D9781B6F27FF47917311BB24B451B9C08D6F25F2FFE913A0520527B3DD8A800D4E35C0B403738F200CF8F884ABAD74D0694E14D62F601905F0E2A681782F4FC992F00350B80FCACF969420DEAF8BFBCBB1B7771BDCF69F10F41FF6B5F04BBC521F37F7113507F8CD8CFFF1D73BD9DD7E9791B7FF7B14501E8D686FC787F4726F4AF9BAC27F9A96165EC0B403D2800E75800DA301F1782C34E02FA30488DD17077601A003B4E735AB25D7FB708E421B10D35FD2F436069C2EE2D00C56B2256C7C3A7FA3FCCFBE0E58FC52EEFFE4F59D05FDD137F0EFF9B9D00E47FFEB1CC93ABF0F97DC9A89903A6F37FC76EAE259BD75D2EE8C2688979016833609CD7879D04F4452F9D181B9E0E52004C0BC0DAC6AE1BE2F9158074DD3F4CEC8F6F6721BEEB04A02785435B02EC82C12C00F62DFE896B2E0116FE0F61B050DC2625509EEE8CF78BD49EF42527F93FBB7E3F9E040C73558E83F47A35CF47FFF372D18D91F1F5B5AE0F9BCDFF7D8B7FE29A4B806D0148E32178FA68BCE973F709404FF2BC1D637699605B00D69EEAE8F5E16C0AC0AEC9291BE0AE8697DD37706E05603628FAC97ED829C068F8F8FAFAC7843601208E840B8FF37130FADABF6FD778A8CC6AFF779DCE0CE1AFC37C6F01D8F9FEBAE560BDFFD3106FE7FCE41E9F2EB4CB8D819AC3B3CD43EBFF740CCD3FBFCEE5009BF92F6EF82DC6493E06461FFBF72D14470B2C0B80F6F5D0538071AC8CAFAFE3798E4501D8755A27B37F97DFD97D03675100F2093E1B00C720EE163FAB02B0E3868FDDDC6EBE1D06535A00FA4668100C1601207DDF51002613BBDF315A78AD58E37F37D9FB32D62ED66531DBB548178B83F074F904218E83E998383514D6FABF34B747DF164A60F477764D57BC569D0414D4182316F35FEE060B2FA70B41367EFAF2573BEC97302B0093B2760CF9E59F3406FAB269B031A85D0072DFE4383814F1D32237BA00447637BBCECCA5D7C486BFAB30582D08260560F5E2DF85BBDA21B683491E179F46FD005838DEDB5900A6FE76CFD56FFB8AE3FD4FC773FD42DC7B5DB6FEE5457C5F01C88EFF4ABF27FF567ADD69A742EBFCEF16EC7257BE74F237781D16FE34C7CBD70EAF590AF9E1DFE91785F8F70A0B42FDF99FF997B3B3004CC3BD7BAEFE699FC2A400AC5EFCC51AD197C576DC18DC0C58D37FB9BB1F10D99E11E7F4AEC2605108AB17808EA5EB3B9DB94B8BFC620130687D39B503607DEB2B76FBE5E3D935C55D474CC7523D009626FF9E023079BEFF8CA505A526EB0B404EF22E232B8153BFCAF71741BFF8BEE97323D75000DA539A54D00EB96C9376F8E13DF9F818DE933D3F7B6FA2FC7762CEA41DE27AAA1700E951604F01983C3F297AB6D49EFFBB3671BB495E96EB47FF78762F49CD5CD8AC00F619B1B43E2C1680D906A11E460520206FFC5953004E9FE0FBA839004E5FFC032240BAF697768E757706B503A05CD8F79DDCE49E8F13BB0F0183C65FB2C6FF798B179E64856DF2BCF0770CFAFC7440940A152E279E0AAD2F00E1DF0E8BF1AFBD7FC9E759B14B1EF60B7FFBBA54F01E753F0A98C640F27FE9332CF2A1F602508E8D7D3BB73C33C671D0FB6C70E2575273FE2F65FB7E321FC506A21B5B8794C4E3A95F000293B99F5853005406D4639302B0AAAD0D83E08C0AC052F3DFC7A4E1A5808FC6678B417E19E04617803449478E2900E36BCBDD9E1D6BFD9F4DD659584F17EBB410C823C089BFE9F1B9CFFBFFCDE339A9006474DEE9D3BFD973B39D7FA40F76B100A4E76E7E01282EEF048E2900E36BFBCF31DCFD25AACD7FE9DB014CE6781A23D1D76C6C4C0AE079158055A738C35A72AE05200E867CF72602A32D0662D0E48521EE0456158823A83300C284BDD34F56D9FE34D3C1D14DFA21042685A25F0CFAC7F685CA31DCA402308E99F4397527BBE264FF1727FB7C31388EA2000CE3E12614C0F9425F2EF2F1EF83B77DC8CF76F639ADF745E80FB9E1A3008C852E7D4E5DAF1575E67FF0EDAA5FC845D62F31CDF6CEFB212F266BC3B41CEECB946330290071AEE6E55CAC096D564C323E7BBC7F5FDC2CAC2A1007625B00DA2FD44DD0F9C45D2E005D108C41721E0520EEF6FAC97A44012819C3A23CEA9D168048AD81615D00068ADDBC5C0CCEB10004C65D7DDED86B1680713CD42C7F9175FE0B9F8B05BC0DE9620197F3BDA79BE7F90E307BFD528128C6D41AAC0BC0C0BE7B0022675B00A26FBDC74714809271612F0BE67CFCD45A17CC0A40FBDFB97CECBF5400BA3130CE770AC0D91480FC7BCC17EC7C7150036298FC6A50149F77734F0076ECF2D614800A01BF8F2AFE179EB593F68422D8D18F97C9E7D43F125CED7F3B7753418B7E757F1EE67A5108DA795C168272C14FCFF7BEA7CFEA16866C91E9DF57231B6A2F0072618FAC290067730960FF829D9FD6A8F56098FB6A4D283EEF2C4E00DAFF6EA70560347834FD38C60155D36C45AD01304CE861D28EBB81D9822D17F95DF405202D0643509C4EED02A02770E080023078DD2F04D6DE476C0AA011060BC27AFFE3E29EE677375FC7853AFC39047AEEF79BDFC273D9EE70BA014805E04FD97B5279C88B45BF10B49F93CAC069545F0096E6F6010560C8897E9ED73EED51D49AFFC37C1EE6F958FE66F378292316C97D0F7F1F360AA7635100C6057F6D61B73BF1CBB12D001393C6B090ED2F1003E1CDA37B93C2105F7B2E05A0244D70D5E0E409404B1C30E2183185C7B01BACB713AC5E00B2893FE18002907674698CD4D8E1EDA38EFF3B8E7E4B668BF811E5A162F14B9CE47FB6A0772C2DCA0B63A264F1C4A7DC61D61B1BF5E7FFC25838A000A4AC48F960B9FB4BD49FFF1D697E2B9F96D680AE088AB192C6C530DED66E2CE7981580C95C8D6362F9342012BD7EFAF1ED49AEC7D79E650190C7BBBD69BB0B8078AE62DB53981480B40B90819D026261115F3C161A9FAB190C2601A01AFEBE02303C9FC2BECE0E6F1FB5FC9747BA2D4796B51DA743166170AAFFB3391BE6AB9EFF39C9DBF9C23E437C5ECD4D81E9FCCFD9570086E75321B4BFFE1F319DFF32BBD302BFB088ABEC489FD33F57736360E1BFCE82430A8078CEA0F4272800019300D8C1E464E0C0EBC429F8D300B9F10520B07F1128E87D4EEFDBE2F83F52CB7F35794FF1A9F6E72D51C3FF5D5E271FA773BB0FFFE2042105FB5246B454CE03ABF9BF5C0817E8833EBD6F8BE3FF88D5FC5F228D95D6EBD90992A61C4314803A5000025B168025F3F791827F1C5847EE2A7760190047978084B1E739360560BE7B3B6841D87379E0269E00B4CC8E66B39D7D51EC76D2BE363F15288B42FAFC7A58CEFFA34B40C230F44BB62C003B8BDD0ED2823F8EA17AE3800250BD00F4473C8BD7F30EA5D6E7EC66AB02B03A0CB2C57EF88CD942B11EB30038B0DD6BEA07FD1275FCCF17EAE9E2BFE47B5CCC170BE1C4DFE5CFAEC1E9FEE7D76C978FF60FDAB5CD8E7FC5E755CE03B3F97FE0E99EA65EC1DFC7560560F56620CB82E1332A8E81FAFEF797784FCEE85A9FB38C69016827FC4FDFB5E6A9E6D73DBF74BDE787E6C778EC131791B32F000B37051D4C0A83F1736AEE04AD02207ABEF6183F4EF4B3BA04305CF3CD17E8E59BFB72FF964F85F24560FCACDAA700A7FBAFAFE357F14FE543E57B43ACE67FF475AD57B134D6F67909FB029017C435A402307E4ECD6CB02A00EDA9ED671F2CEEFABBE797EEF7FAB0F936FA1F4BE4F91580F911DE9A02307E86EDCD60A60560C70D5D87931695BC48D4DB09DA05C00913FFEC2E01740B74BA54B3D37771A4B7EB7468FA99F5778635FCCF7777B3703EF62448799FE744E5B16137FF4F28FE9772094016B86349F9AF4E9A4EA7BEFF79F1EFE6EB9A026079EA97B02900271DFD2A6C8F83CD0220995B71320F0B45C5CFB40D801F8689AAAFDF8D452F2D1CE58F825A53CDFFE877F0657947DFA17676FBDF137604695751BCF7546AF9DF957C15D653E4EE6D61A1185FDB8D939A3BBF845D01087CF6E110DE63C9DB7DB253FE28983566F33F795AB1B00D1952F133ABFB7FD2A51F45FDD29F302900D58F6F63A130DC119A04C03008EAB6B7732B00BF5EA5C57E7A4C3C5E0F9E3E9EB008FA256AF9BF6F11CF992CE4BB4E0B0A2C8E85ABF97F60F197F7021CB453B4D908581680EFEFA4F0CE7774B9FFD3C7135B1DFF474CE6FF3016EA9EDE9E4301A87EF926AE2515F33EA77E01A872E4A391C151018B00D875A45B877AADD0AA004C2FFB4C83603C0D2802221B3F5B95802AFEA7C217AFD71DB803583C029C11BD4EC7C9F58F036BF93FB9E763670E140BF99EE290E6FD29F794ECC2AA004C0BE1D4B7311F0A3FB3F1B05509B098FFE3FCB6A25E19ACEAFF1165FE582C4EFF2A1780536FF6D883D1CD80D503A0FA11D002955AA155013839040C4F7D726AF8DF857D16E61583A0DC2DD65E18EA1580FCD24DA52CC8E77C280AF7CFA8009CBC0930DAF595549FFF079E049D4CA57CA8E7FF09F77C1C82C1CD80750B80E1EE3F61710A503B00F2895FBFB5E54786754E01AC0AC08403C786D529CF2EAAF8DF2EF8A31FEA72C0FEB1A0036458F0DB6259EFE42751CFFF1F9AFB29948B45E0385FF3CB42E34EEFCDA3EFAA1E2727AC0AC084030BA1C52E6F1FB5E77F5EFCEBCF673D364EA19AFF86BBFF44EDF151B5008CD77B8D88A162B02BAC1B006981AE1FD423E342516337B83600E244DF3DC1F5F5FDC3D87FEDB0BDC450613CD4F13F79F25EF3F59D6CF15FBD8B9B96814FEEDC6E4F952C8E856B2E0093CB3E8B2776E5B858CA8DE92982D525A1B5FEC7A2BF3B90F5F5FDC3D87FA9A72D99154E09EA1680E4ADE55A308E8B1A63A256FE8FF77B1861702F40C502104DD9A000185C06A85A0086E3FFCB2F00A72DF035A87383513DFF0F3C9D119788167DCC5F6BF4F3C0F51680713C94C17CD4E5A0A2D48DA5A2EE0D6589F5FE9FB2C0D7A0CEFD20550BC070F2E3AD00C44CDEA00054CE80CA05201F9C46DCF402B0C13150CEF5168013AEF3F73E9E749FC08DBB06988EFEB320108BFD61CC3FC3EA78D8B200D4F0F7E6168013AEF3F7417ED27D0237F11EA00D2E03E7DCAC02A0FF1BAB4201A000E45C6F0158E7F9ECB2C1DA9B862A8D85AAFEB78B75DC99550A8476C2C79D669DDD9EA2E60230B9045019ABFB43D6FBBFCEE359915B5B122B2D0614000A4026C8B3E6F5D547E38BAE1E34EF86E77641016859BDE35BC7B51580A327FA214782950AC59154F53F52BD04DA1E2D565D005A2A5F1A32B8EF276795FF477B7C8887950AC59154F57F6D995F0905E0348A02D02FFED9A2FFF6E1F4EFBB38E9B8EF500CC2A0EE02B0ED75C1EBBE047009542F0019A7FD2898F135C59E4DFC3FA2305AEDF497B0F4FF1CA8EBFFB6F705DD9C0270EA5C3F10D39B005F3E685E7C79B779FD3213483D766110001400A58B17F01FFF952E5EF0EC3F0520400010004A172FE03FFE2B5DBC4001A87409E05C21000800A58B17F01FFF952E5EA0004C6E02EC17FDF4A20B5FFC23040001A074F102FEE3BFD2C50B1480A1003C6E5E7D1916FF878F0771BA32C025804B8600C07FA58B17F01FFF952E1E981680E7DF8407BF69DE66E2A452F0EA79FED865410010004A172FE03FFE2B5DBC4001A000CC84F1040180FF4A172FE03FFE2B5D3CB0F712C0BB2777C30BCB52705910000480D2C50BF88FFF4A172F5000263701F6256078D1652FFE1102800050BA7801FFF15FE9E2050AC0A400F883002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E281B600FCE7EF7F6E45F0CABFFFF6B49D045EF9D72F7F94BA7801FFF15FE9E205FCF7EB7F5B007EFFF90FB21D78210A9137426FC449A074F102FEE3BFD2C50BF8EFD77F0A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1ED8BE007C76BBB975EB96E4EBCFC4EB3760D301F0D33DF9DD23F77F12AFDF804D0300FFE5778FE0BF78FD06E03FFE2B5D4CB861FE6F5A009E7EFC9EFCE213EE7C28DF6BC95603E0CDA34FF577CEB9FA41BED792AD0200FFF15F7EE71CFC97EFB504FFFDFABF5D0150CDEFFD0F9AA7E9F9CF3F683EE91FDFBA096E320054F3FBE2BBE64D7AFEB7EF9AAFFAC7B76E829B0400FECFBF3FFEE37F7A1EFFF1BF7F7C4BFF372A00779A6FDF2FBE7C64D2F63E6CBE4E8FE7036303EC07C09F9A1FBFC8BE7762D2F67E68EEA7C7F381B101F60180FFF89F7DEF04FE67AFC17FFCEF1FDFD0FF6D0A40D6EEA6BCD77CFB79F79AE9F1D0F8F816980F80ACDD4DF9B4F9F1B7EE35D3E3A1F1F12D300F00FCC7FFC9F74EE03FFE77AFC1FFEBF1FF9A0BC0125E06C0125E026009FCC77FF13946E03FFE2B5DAA7183FDDFE8124076BC7310B79BEFE5E7D8603E00F2E39D83B8D7FC2A3FC706F300C07FFC97DF7309FCC77FF5393678F67FB39B000FBA0334B1F19DA0F603E0C03B40131BDF096A1F00F88FFFF82FBFAB02FFE56758E1D9FFCD0AC0E28D20251BDF0012D962002CDE0852B2F10D40912D0200FFF11FFFC5F72DC17FFC97EFB761C30210D93308AEC1FCC8360320B267105CC3E48F6C130011FCC77FF1BD13F88FFFF27DB678F6FF9A0A40799347BA46B4EDB59FC4F603A0BCC9235D23DAF6DA5F62FB00C07FFCCF1FC77FFCC7FFEBF07FDB0230FC3288A501703DBF0E72B30130FC3288A501703DBF0E72B300C0FFFEFBE33FFEE7CFE13FFE5F8FFF1B1680D1E4DD6CDF02B71900A3C9BBD9BE056E1300F88FFFEAFB96E03FFEABF7DBE1D9FF6D0A80FA35903B291BA22DE60340FD1AC89D940DD116F300C07FF11D7781FFF82F3EC708FCF7EBBF7D01187E094434B5BF06D4FE9847FFE7FEC68FEEC74442FB1B06CB764DD074000CBF04229ADA5F036A7FCCA3FF737FE347F76322A1FD0D8365BB26681A00F88FFFF81FBE0FFEE3FFCDF3DFBE004443B3BB3B5BA3B3BF777483E1938FEF4CFEBED5F520D301100DCDEEEE6C8DCEFEDED10D86AF1EA5FF8EEEEF5B5D0F320D00FCC77FFCC7FFFEEFF87FB3FCDFE012C0A1D77E4A2EA4011E7CEDA7E4427600F88FFFF2FBED03FFF15F7D5E7D3CFBBFD94D80DFDF515F72810BFC4D50BF5E89EFB9C486BF092A621B001DF82FBEE712F82F3FC30AFCC77FA54B4D6EAAFF9B1580636E04D9FA4741B61800C7DC08B2F58F826C1100F88FFFEABB2AF05FBCDF10FCF7EBFF4605A0BBA6A3BE6C477FDC9306C9EC1A912DF603A0BBA633FFDE89FEB8270D92D935225BEC0300FFF1BFFCCE39F88FFFE175F8DFFD7D43FF372900DD1D9EE5979E925ADFF0DA0D0781F500E8EEF09C7FE79CD4FA86D76E3808AC0300FFF1BFFCBE25F85FBC16FFF1BFF81C0BCC0BC021E6B764860FD78B361A049603E010F35B32C387EB451B0D02CB00C07FFC9F7D5705FEE37FFF1EFC9F3F6685710138EE0ED0E1DACFE46747F3CFB3C16E001C7707E870ED67F2B3A3F9E7D9601700F88FFFF3EFB904FEF7EFC37FFC6F1FB3F7DFB6000C461EC8D0F8C66B46C3A030C46C000C461EC8D0F8C66B46C3A030C42C00F01FFFCBEFB80BFCC7FFF6BDF8BF95FF860560DF8D1F9ACEF0FCBDF63F0F6A3300F6DDF8A1E90CCFDF6BFFF3A0360180FFF83FFD6E8780FFE57BF11FFFCBCFAE87610158FB0B204AEC8F816C06C0DA5F0051627F0C641300F88FFFEAFB1C0BFEE3BFFAFC7A78F6FFC69D00CCF1D500E7F8DA01CCC17FFC579F5F0FFCC77FA5CB699C87FFB6F7001CF1CB1F9638EB6B4047FCF28725ACAF01456C022080FFF23B1D03FE8BCFAD0CFEE3BFD2E564CEC0FF0D4E00D636B8FE0869831F05B16D806B1B5C7F84B4C18F82D8EE00F01FFFD5F3FBC07FFCC77F6BFFCD0AC0F0B39C27FC5EE7E167488D7F37B4C500187E96F384DFEB3CFC0CA9F1EF86B60800FCEFBF3FFECBE70F01FFF11FFF4FFB8C7D1815805AD77F7ACE6E00D4BAFED373760180FFF82FBEC75AF05FFC1BF5C07FBFFE530002040001A074590FFEE3BFF81E6BC17FF16FD48302400190E2AC8700C07FF13DD682FFE2DFA807FEE3BFD2653DE75A001E3E962F6A79FECD4CB8652A0F00E31B416EFC0030BE11E4C60700FEE3BFFC77EA80FFF8AF7459CFF9F8BFFF04A02D05CF9AD757E2B90BA1FE00382FEA07C07981FFF8AF74F102FEFBF57F4F01F8A6791B9E7FF7E4AE78EE7220000800A58B17F01FFF952E5EA0002C148057CFC38B5E3E685E88E72E0902800050BA7801FFF15FE9E2050A802A00570F9A77E1B9B70F8BC72F1002800050BA7801FFF15FE9E2050A8028002F9E3C73B1FB8F10000480D2C50BF88FFF4A172F50006605E06EF3FAE5E55FFB4F10000480D2C50BF88FFF4A172F5000CA02D01EFF5FF69DFF39040001A074F102FEE3BFD2C50B1480B200B43FFAF7B879953F76C110000480D2C50BF88FFF4A172F50008A02E0E9FA7F84002000942E5EC07FFC57BA788102501480F6C7FF8EFACD7FE70D014000285DBC80FFF8AF74F10205607613A02F08000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1E680BC0BB7FFCDC8AE0957FFDF2C7761278E5DF7F7B2A75F102FEE3BFD2C50BF8EFD7FFB600FCF7F7BFCA76E08528846A865E889340E9E205FCC77FA58B17F0DFAFFF148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F5000CA02F0FC9BEC45779BD72FB3E72E1002800050BA7801FFF15FE9E2050A405E00FAC5FFD5F3EEEFEF9EDC0D7FBFEC12400010004A172FE03FFE2B5DBC4001C80AC0DB871F357F79F83813E871F3EACB8F9A174F9E658F5D16040001A074F102FEE3BFD2C50B1480A100748B7DDAFD7B81002000942E5EC07FFC57BA788102900AC0CB07CD8BF6B8BF2B02E945975E0808000240E9E205FCC77FA58B17280093021017FE6F9AB749A0F69E00EE01B8640800FC57BA7801FFF15FE9E2015900A6D7FB9F35AFAFCAFB022E0B02800050BA7801FFF15FE9E2050AC09E7B00E637065E16040001A074F102FEE3BFD2C50B1480A10074BB7D7502C04F015C2E0400FE2B5DBC80FFF8AF74F140510002C5357F7E0FC0E54300E0BFD2C50BF88FFF4A170FCC0B4084DF04E80A0200FF952E5EC07FFC57BA784017006710000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3CD01680FFFCFDCFAD085EF9F7DF9EB693C02BFFFAE58F52172FE03FFE2B5DBC80FF7EFD6F0BC0EF3FFF41B6032F4421F246E88D3809942E5EC07FFC57BA7801FFFDFA4F010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205800220C5F1020180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C503148000014000285DBC80FFF8AF74F10205202F00570F9A77C58BFEF7CFC7CDAB4CB04B83002000942E5EC07FFC57BA788102901780878F9BFFBD7CD0BCC804BA7408000240E9E205FCC77FA58B172800590178F1E459F3BFE7DF4C04BA7408000240E9E205FCC77FA58B172800590178F5FC97E6DD93BB13812E1D02800050BA7801FFF15FE9E2050AC05000EE36AF5F8602F0F259F6A2CBBEFE1F21000800A58B17F01FFF952E5EA0000C05E09BE66DF8FB7802D015026E02BC6C0800FC57BA7801FFF15FE9E281F94D8025FD4F05BC7D289EBB1008000240E9E205FCC77FA58B172800BB0A407F2A4001B85C0800FC57BA7801FFF15FE9E2816901883F02F8CF67CDEBAB4CA0F604A078ECC220000800A58B17F01FFF952E5EA00014F7008C3F06D8DF0370E1BF1780002000942E5EC07FFC57BA78810230B904D0978084835F0A440010004A172FE03FFE2B5DBC4001D8790FC0E5430010004A172FE03FFE2B5DBC4001A0004871BC4000E0BFD2C50BF88FFF4A170F500002040001A074F102FEE3BFD2C50B14000A8014C70B0400FE2B5DBC80FFF8AF74F1405B00DEFDE3E75604AFFCEB973FB693C02BFFFEDB53A98B17F01FFF952E5EC07FBFFEB705E0BFBFFF55B6032F44215433F4429C044A172FE03FFE2B5DBC80FF7EFDA7000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102B058001E37AFBEFCA879F55C3D773910000480D2C50BF88FFF4A172F5000160AC0DB871FB52FA2005C360400FE2B5DBC80FFF8AF74F1C0720178FE4DF397ABBBCD0B4E002E1E0200FF952E5EC07FFC57BA78401780970FC2C27FB779FD924B001E2000F05FE9E205FCC77FA58B07440178D6BCBEFAA879F1E459F83305C0030400FE2B5DBC80FFF8AF74F1C0AC00BC7B72B7F9CBD583E65DFB770A80070800FC57BA7801FFF15FE9E2816901188EFE933814000F1000F8AF74F102FEE3BFD2C5039302D0EEFEC58B5A1E3E9E09772910000480D2C50BF88FFF4A172F5000CA9B00073801F0000180FF4A172FE03FFE2B5D3C40010810000480D2C50BF88FFF4A172F50002800521C2F1000F8AF74F102FEE3BFD2C5037B0A800F08000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1E680BC07FFEFEE75604AFFCFB6F4FDB49E0957FFDF247A98B17F01FFF952E5EC07FBFFEB705E0F79FFF20DB8117A2107923F4469C044A172FE03FFE2B5DBC80FF7EFDA7000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102400190E2788100C07FA58B17F01FFF952E1EA0000408000240E9E205FCC77FA58B1728001400298E170800FC57BA7801FFF15FE9E2010A4080002000942E5EC07FFC57BA788102302900779BD72FB317BD7CD0BCC8C4BA4408000240E9E205FCC77FA58B1728004301E817FFE7DF2CFCFD3221000800A58B17F01FFF952E5EA000A40270F5A079F7CF67CDEBAB4CA0878FC30B1F37AFD2DF2F1002800050BA7801FFF15FE9E2050AC0AE7B00DA025094820B83002000942E5EC07FFC57BA788102B05800BE69DEC6177209E0A22100F05FE9E205FCC77FA58B07160BC0ABE7E945977DFC1F21000800A58B17F01FFF952E5EA000ECBD04F04BF3F6A178EE4220000800A58B17F01FFF952E5EA000EC2A000E7E1280002000942E5EC07FFC57BA788102900A80BCE39F0270E91000F8AF74F102FEE3BFD2C503C509C0FCA6BF174F9E8517F25300970C0180FF4A172FE03FFE2B5D3C202E0114BF09909B002F1E0200FF952E5EC07FFC57BA78E0807B002E1F02800050BA7801FFF15FE9E2050A0005408AE3050200FF952E5EC07FFC57BA7880021020000800A58B17F01FFF952E5EA0005000A4385E2000F05FE9E205FCC77FA58B07DA02F0EE1F3FB72278E55FBFFCB19D045EF9F7DF9E4A5DBC80FFF8AF74F102FEFBF5BF2D00FFFDFDAFB21D78210AA19AA117E22450BA7801FFF15FE9E205FCF7EB3F0520400010004A172FE03FFE2B5DBC4001A0004871BC4000E0BFD2C50BF88FFF4A170F500002040001A074F102FEE3BFD2C50B14000A8014C70B0400FE2B5DBC80FFF8AF74F1000520400010004A172FE03FFE2B5DBC4001A0004871BC4000E0BFD2C50BF88FFF4A170F500002040001A074F102FEE3BFD2C50B14000A8014C70B0400FE2B5DBC80FFF8AF74F1000520400010004A172FE03FFE2B5DBC4001A0004871BC4000E0BFD2C50BF88FFF4A170F500002040001A074F102FEE3BFD2C50B14000A8014C70B0400FE2B5DBC80FFF8AF74F1000520400010004A172FE03FFE2B5DBC4001A0004871BC4000E0BFD2C50BF88FFF4A170F5C4B0178F3E8D3E6D6AD5B05F79A5FC56BB760EB01F0F4E3F7C4F7BFDD7C2F5EBB055B0700FEE3FFFCFBE33FFEEBD75BE3D9FF6D0BC04FF7C4179FF2D5A3EDDBE86603E0B3DBF23BE77CF2F11DFD5E43360B00FC97DF3907FFF15FBED710FCF7EBFF760520997FF5837E3E909AE1D68360930190CCBFF3A17E3E909AE1D683609300C07FFCC77FFCC77FFD7CE03AFCDFA800FCA9F9F18BF0E5BFF8AE79A31E8FC2F44740BF5E8D7F9E7E861DF603E04EF3EDFBE17BBDFF41F3543DDE7EFFEE08E8FB3BE39FA79F61877D00E03FFE87EF85FFF8AF1EC7FFC1F3ADFDDFA600FCF65DF355F892F366F74373BFFDF21DF77F4A2DF0D3E6C7DFF2D7D9623E003EFFA0F9247CBF79B3FBB0F93AFBFE5F7F965AE07BCDB79FE7AFB3C53C00F01FFFC3F7C37FFC9F3E87FFD7EDFFA605201A5C3E978E7D523BBCE401100D2E9F4BC73EA91D5E7200E0FFFC39FCC77FFCC7FFEBF2FF9A4F00E67447405E1AE09CEE08E8320300FFF15F3E9F81FFF88FFF97560086A39E7DD776FAD7CDAE15D9623E0086A39E7DD776FAD7CDAE15D9621E00F88FFFF88FFFF87FE3FCDFA80064473D4B83A06F89F135EAA8C812FB01901DF52C0D82BE25C6D7A8A3224BEC0300FFF11FFFF11FFF6F9AFF9B158096037E0E746BF3235B0C8096037E0E74EBC91FD922005AF05F7EE71CFC17EF3306FFF15FE9529D1BE8FFB60520D05DE3D11C728DC882CD0640A0BBC6A339E41A91059B054000FFF5778FE03FFEABF75883FF7EFDDFB4000CC740B36B3CD9CF83EEF84511566C35008663A0D9359EECE74177FCA2082BB60A00FCC77FFC0FDF11FFF17FF2DCF5F9BF5901189BDFD28D20D73708B6180063F35BBA11E4FA06C1160180FFE9FBE33FFEABD7E03FFEF7AFD9D0FF0D0A4066ECA2F989ECB51BDE096A3B00326317CD4F64AFDDF04E50DB00C07FFC4FDF1FFFF15FBD2681FF5BFB6F5E0066C73EFD8D20F9F59EF49AEEB171106C754388E500981DFBF43782E4D77BD26BBAC7C641B0D50D21960180FFF8DF7E7FFCC7FFF818FEB77FBF29FE6F570056900F124B3619002BC80789259B04C00AF01FFFD567D606FFF15FE952839BEEBFFD2580E2473F0653879FFB1C7FEB5339582EA101963FFA31983AFCDCE7F85B9FCAC172093B00FCC7FFFC3BE13FFEB78FE3FF8DF07FF39B0077B5BA61006C78FD27623A007AD24D20BB5ADD300036BAFE93300D801EFCC77FFCC77FFCBF59FE6F56008626B8E30ECF430689055B0C80A109EEB8C3F3904162C1160180FFF88FFFF88FFF37CBFF8D0A40BAB143FD9F3CF4CFC581918E852EAE01A61B3BD4FFC943FF5C1C18E958E8E27600F88FFFF1FBE33FFE2F3C87FFD7E2FF3605405CEFC9E98E7EE28F88A4FFD308FD3A2BCC0780B8DE93D31DFDC41F1149FFA711FA7556980700FEE33FFE2FFA8AFFF87F5DFE6F7A13E0E24D1D6980E42D70D7EB2B633A00B29B40166FEA4803246F81BB5E5F19D300C0FFE1FBE3BF783E82FFF81F5F83FF9BFB6F5C00761DFD4C49378074A66FFB7F0B693700761DFD4C49378074A66FFB7F0B691700F88FFFF88FFFF87F53FD372E00BD91B1D9C9E73386E6D7FDB6A8EE8690EECFF2F515B11B00BD91B1D9C9E73386E6D7FDB6A8EE8690EECFF2F515B10B00FCC7FFF03DF05F3C5780FFF87F0DFE1B1680D4FE0E3DCA29DA621A101BB4409B0190DADFA14739455B4C03628316681300F88FFFDDF7C77FF57C09FEE37F7CFDB6FE1B168015C738F17AD1D016D380B06F81360360C5314EBC5E34B4C53420EC5BA04D00E03FFEE33FFEE3FF4DF6DFBE00AC3670C5005A89E900586DE08A01B412D300C07FFC97CFEF03FFF11FFFADFD37BD0720FD6287436E02999206CF36BF14C266008CBFD8E1909B40A6A4C1B3CD2F85B00900FCC7FFF4FDF11FFFF56B34F8BF95FF1B9C009CCAB183E7786C1BE0A91C3B788EC77607702AF88FFFEAF3EB81FFF8AF74398DF3F0DFAC00A41FEBA8C22177919E80C500483FD6518543EE223D018B00C07FFC97DF650DF82FFF8D5AE0BF5FFFCD0A403AFE39EC0ED005D22F9138C301908E7F0EBB037481F44B24CE3000F01FFFF11FFFF15F3F7F101BF84F010810000480D2E514F01FFFF11FFFDD17802A9CF100A8C219074015F05FFE1BB5C07FFC57BA9C02FE8BEFB1966D0BC0E3E6D5971F652FBADBBC7E3915EC101800E27BAC850090FF462DF01FFF952EA780FFE27BAC05FFE5BF5183A2003C6B5E5F85C5FFEA41F3AE17E7EDC35806D6958073C162009C131601704EE03FFE2B5DBC80FF7EFD9F1680E7DF8407CBC5BE2B052F9E3CCB1EBB2C08000240E9E205FCC77FA58B1728003BEF01A0005C3A0400FE2B5DBC80FFF8AF74F1C0FE02204F052E0B02800050BA7801FFF15FE9E2050AC0520178F9A079F1E565EFFE23040001A074F102FEE3BFD2C50B140055009C2CFE1102800050BA7801FFF15FE9E2050A405900DA63FFFF73B1F84708000240E9E205FCC77FA58B172800590178F7E46EFBC4ABE773A12E1502800050BA7801FFF15FE9E2050A402A00FDB1BFA7C53F420010004A172FE03FFE2B5DBC4001E80B40DAFD2BF831C0CB8500C07FA58B17F01FFF952E1E58BE09D011040001A074F102FEE3BFD2C50B14000A8014C70B0400FE2B5DBC80FFF8AF74F1000520400010004A172FE03FFE2B5DBC4001A0004871BC4000E0BFD2C50BF88FFF4A170FB405E03F7FFF732B8257FEFDB7A7ED24F0CABF7EF9A3D4C50BF88FFF4A172FE0BF5FFFDB02F0FBCF7F90EDC00B5188BC117A234E02A58B17F01FFF952E5EC07FBFFE530002040001A074F102FEE3BFD2C50B14000A8014C70B0400FE2B5DBC80FFF8AF74F1000520400010004A172FE03FFE2B5DBC4001A0004871BC4000E0BFD2C50BF88FFF4A170F500002040001A074F102FEE3BFD2C50B14000A8014C70B0400FE2B5DBC80FFF8AF74F1000520400010004A172FE03FFE2B5DBC4001A0004871BC4000E0BFD2C50BF88FFF4A170F500002040001A074F102FEE3BFD2C50B14000A8014C70B0400FE2B5DBC80FFF8AF74F1000520400010004A172FE03FFE2B5DBC4001A0004871BC4000E0BFD2C50BF88FFF4A170F5000025B0C80378FEE353FFEA69FBB6E08806B0880DFBE6BBEBA75ABB975EBD36B1F17F84F0150BAD4E4E9C7B79B6F3FD7CF5D3714000A8014A726BF5E8D61FFE6D1A73722F813DB04C07BE13B470D3ABEFE2C3D77A7F9F6FDF1F15BEF7FD03C2DDE6BCDE601F0D3BDEEBB7E71AFB9FF45F7BDEFFF245EB711DB1780C2F35BB79BEFE5EBB6610BFFBB393F7EE7D1EF3F353FF663A0E58BEF9A37C57BADD9C2FFEFEFC4EFF75E5B02BA2CE8FEAC5EBB351400D302F061F3F59D0FC7BF7F767B1CEC05E3A21007CC76A1B05D01087CF169BFF38BDC8C12601E009F7FD07C92F9DB86415AE8DBF190BC0E6325BCEE938FEF4CDF6FCCB601D0057EBEE0B78BC335047F62CB02D02D04D3B93E94C33C2736C4DCFFFEB42779DE6641F2BB2D83F79A5FDBD7FED0DC0FAFFBEAD1B60BD2760520CEFBF7DA2CE8F2EF6694005BFF83A7573F8C7F4FE55F9067C2AF57694CD8625700260B7DB6981F5400A63B843C2C2CB05F00FA961F07423F00A2D9F9AE20377F6BCC0360B2C807DA42D0FD3D0643BEE0B741B1F14250DFFF2EC83B6FCB893C2F00D34520917F866D51DCAE0074052F7EA7DCF3F17468BBD29F633EFF4B7FDB42D0FD3D96817CC16FCB41BE606C80BDFF7D9EC779DDE77FCCF4FC54D03AE37761E2FF64A1CFBC3FA8004C4F852CD786EA0560687A91B0CBFBBE35B92C0045F32B768869C07CF2F187D3A342A385C1BE00F4612E26F6703290736901A00A407F02305DF0B3A048AFDD80AAFEB7E13E2ED86A773FD901E6E570784DB1136C43C3AE046C5D00E2E29F7C4FFFDB2D068E0A40EFFF74C15763C11E7BFFFBE227E6F564BD489CF1FC9FE479F0F8D77693571680622E172744691C7CF5E8874911B01817550B406A74F3765F84FFC10560BE4BC81FAB856D00646D4E19A81AE1C50540BFB0B78B7E1106E24468EBDD404DFFE3823F3DC28DFE17135E783E3B1110A5C1EA68F83A0AC0781AD065C34517809401ADA7C56660DF58D8005BFFFBB91FBF9B5AD8C5FC3FD702904E74F379DA3D569EFE1C5A00CACFA99F01F50B407113575AB82714AF990C928CE9623F2F05B5B00C80D4080F9AD479186C5802B65800E43850CCC6863DB50BC0D4BB18F8590044260B7CB7204CC6471B08F97BE68150935AFE2F7B9C16F67ED19F5C078EBCD77C7DA728006A61089CDF06A02305F85E8AE2B70596F33FEDF00F2AF5B9E71B9680AA05A0F04FFA3EF338DB24664CE7BB4D06981780B4BB1FBFD852CB4F3B82447983C8F91580CEFC238F6EFB36D8696077EC9BB3D50E601202C364CF7C1EC6CAB6370755F57FF02F2CE0E9CF65998B056078AC9BD865419C1C25A6CFCB9EAFC9C9FE4FE6783EBFCB397D24932CC9370975C7876D0118C37DE2F150F6B3393E8C9D6DE67DC26AFE7785F048AF2663699B1CB02C00D33C8F2CCDE3FE6468A01C03E75A00AA716605200FFFC931DF01419E0D1AAB5D5F8EF90E60C798E87608F9444F41BFDD717075FF73FFAEEE853F4F3D6F83A22800539F63187CDADCBF4ABB07BBC53F7292FF29B00F98F7E98440CDE163768A47ED2A0FC0B200B4456EC7AEBE2B7A79D8A7C260EB798EC9FC4FE322EEE427A73907CCEBAC0458E47D896901A8C605148014003B593CFA39A702309DC49363A0723798F3DB9FC6C1939706B341D561BB0318277C0AEE481EDEDDE362E7B8D131A095FFDD8E2FFF73C7B40088EBFBD92582F2B516ACF7BF2F6BC39CD73BFE6ECEEE9BBFFD67F59EE76365642C8AF331B31EAB02D0CDFB7121CF4F75F2F1D03D9E2FF8C57D02C6D49FFFD3123FC9FD5D73FAF33BE3DA919706B34D65C7560560B20E2CB1E8F9B91480F68BF41373729CB38E6EA11883E51C0A409AE8E5B1EE5E42F0E706E703E6E8CF3A029B02D079365DE8BB7111C37BBA7BEB5E3BF1B60D809B7C04B8FBC8AE1D03FD642E17F1F8F7DCE7B200E47F2F9F9B9E26454EDF29AEF6BF0FE9E91C2D16E514E4ED75FF053FE36BC2C2D0E547785DBB78E831327EBE18332BB12900F37B3BD2CF76474FA7F3B97BEDDCE76D2E05D49EFFA9BC4DFD3B80300E723FF3E270F4671D41D502D0FEF7F6737276FC7F3CDD3819B36632462A50B50074A4895AD036BFF85C111003B1358E0BC4ECFD8BEF3B9D9A019006C1FD9F7E687E3CD2AC72A1188D3F3DE477615100DAC95B34F7E5021068178ADCE3E98ED09235FEB75EE56D3FDBB5CF9E6F8360F4B05CD4A7BE47CF53F0978B48F9F73ABB82B5FEB7F3B4F7B80BEB85393A6C04F4F3F1BD6DF0A7B2B058FCA68B7EFEEFCF5F7B38160560363E02CB0520D02EF8F93CEF4F11177784F5A839FFD3A2FDF5671F36DF1E59CEDAF74EE67B59FA6CA8EBFFB8584F687D8CCF2D6579F47B1C1FB3F71BAD010605A0A31B08E5443EAC000C8FF5C151A3E5EFA27603BC1F267A6BDA5193B71B386598A7CF8CD46E7F89FA05601AD4899D05A07F4FFE783B868C8FFF226BFC9FEDCCCBC93D59F4A79701761680BC48B49F91ED028B2291DE7B3D05202F68DD9F77CED37E719FF83E14832E27C6C5237B4DC1C1A5E308EA17003D97771680FE3DF9E3AA4458506BFE0FFE8579DE66D651E55D6746FACC88D53A605600672738871580E1B1FE04C12AF7231480408D019016EAAFBEE817EC239B7BF7FE71C1F8F5A7F4DFD40543FBD94603A17A01687D1BBD6F43BBFD0E9DBFF9A4CEC33EBE6EE275F13956ACF17F16CEC50940E7DB1800F9EB6501689F2B76F47B3E33158B53C7C52905A0F36B5EDEE6F485212F74D1DF6191E83E635FE19B2CFAB353A375545F008AE236EEE8BAF99DB222922FF8B352591640236ACCFF34A73F79BF9FDB479EDC4D7C0D63E5FBCF520EF4E3227E3605A03A1B14807EE2F7261E4E180CE75200DAE3BB68D477DD623D59FC83B15779880B86F777FF1DE50E210588D540A85E008A605EFAFF75886364B6E39F1D01DECC029016DFE84BEB9508EB69A077452E8D91C90EB07F6F77D7FF18026D88E463A97D5DB1884C0AC23A2C0B402A7FEDEBD211FF6C911F433E7E465A4CD422D23E97DE7F530B403B9F471F977EAF7BF470B6E39F644759F86C3879FEF7BE7EF2F1079D8F13DFC238B9B3BBD48DEFEF72BE3C219C8CA1F49E8AD8168031278E238C99732E00E3AE2FB2BC0048535350248E6C93C772DA00E882BD9DB8B31D5B47B780EB10488B7B9AF8EDDFCBCFE80B428DB057D42E0093900E8C63A11B07F9D8982C1AD1F7C9E2B0BCB0D4A486FF6D90F73EA550D70B78F8DE9390EFE8C6C1BC400C0B44FED9C502732AA714806E6EE67F1E5F33CD80F8FCED61A1D784E7CBF71465A1FDCCFEDF29C7D95A6A2F00ADEFD95C1DE678EFD9F8F7A208CEF2231B5BC363F5396DFEF7E52D7A329BBF1DDD38D06BC030467A4FDBBF979F91D6830A5E2B2C0A40EEF1D25C8DE3442EEE29EF13222F6A615C0052E0AF2800ED80C80657F99A8A9C3200BAA6B73B8CA78341902FFEFD22F0E6A71FC620480B47F6DA9A581780C4EE7B00026759008AC04F9337F8542E04C7D1ED1C62F8E7E3A2D6B17FCE5AFF739FDB3FE7215F5CBEE99EEFC7F06C6C4C4F09874C68833F3F01EAC643BE53AC910DD60520B1FB1E80C019168099EF8261915F225FFC7BBF9F7EF6E13846FA93E0FCB535B12B00C9EF1505A0CDF96C7359BEA612B605A09FE8C716807650B546EB9D456D4E1900B9D1F911EDF4F968E27793A3A0A9F1BDD1C38059787EF562B29BDA05A00BEEB9E7FB0A40EBFBAC00DCD44B0019ADEFF9EE3DF979E2429DCA44EEBB1863A7B2DAFF7C81EE433AFA3A067E3E063E6CBE0FCF750B46E969B6B07FF6C1F85C19FC9342302D03A7507D01687D9B7BB4AF00CC8B431C47D353210B4E99FF9DD7BDCFAD5FD3793F8C853BC15755F25A3A2FD3E7C4F7C8E767C5B10E6605A0F7F2D802D08E8376D1EF2F1F9C5F01E817EE68583B69A3B9C712277AF639F2DFA9C32903A0352BFBEF1E0CCD76EDA3C962216FC3A29FE4E93DB385FECC0A40B618E48FEF2B006D58E4654F048A053502A09DF086133561F1EFACF73F5F84F35D7CEF59D8C58DDEDD699E2E2DDC0BE3253EFE75FBBAB440045216CC4E07D6537D01E8E771B9C8EF2B00336F0DCA9EE294F9DF15BAE47BE66BEFE9E431B5908B1239CFFB732B00FDC21DF33A95F8A3896B42F639F2DF391DDB02D07F997162472397023DBE677C6E688E911B5C0022EDC44DFFAD7102F7A6CFDB5DBF906793FC4D3039BFA14C87FBB8A3B4380EAC5E0092FFC5C9CDEE02D0BD277F7C7E2260439500C88B9C7ABE0A363BC25A3BC06131183C4B8BBE784F3636BAF7895C187E33DC982793B251E964D06C0128E6F2EE02D0BD277F7C7E2260C3A9F37F92D5C3494D51F25AFA853CF73E789CFBAB3D1D0BA0DA389C8A99FFFD7FF3E8699CBF4B852EBE677C6EB2A69C6D01904DEEB002303EA63EA72E7506C0B8482F99964E0B26C5E0A085237D76BC6BB8F660B52800813E04F2099B07C56C22B7ED3FDFD175937E1E22F5A9E37F37E9D5915ECE646297C8F23762B5209CE47FBF6BEB7C9A07FC8C6C67285998EB79D15063EB14EA2F00817E13902FE8B9F7B302D0EEF6F31CE8E6FCBEF154833AF37F5CA45B848FA9204EE6F4412739E9B3E34F0DD5CF03B302309BAB871780F131F539F5302A004B41101F3FA6001413DF08930028198E8256ECE0162F0DD4C1A400048EF1AE7D6DBE3358DA151A50CBFFF1DA5DF1DCE07D470AF5B820747FEE277AF69AF90E317FFDFCB953A8B303ECBC52BE75CFAFA35BE4FB8D403B3EEA6F0AACE67FB7E02F05FE94F6B5F9C960BB5938ECBDA76235FF27F4A56DD5659BC54B0375A8EF7FBF619B65C1B105E0B831B4060A40C0BC00A4053CB02AC0B3F7AB85E154EC02A01F07FB266EB90BA8BCC3DB472DFF670B74B6F0CF7DEB177D5118BA493F7FDF8D3C01888853804FEEDC9EECF48FF6727652D08D8FAE60AC5844766037FFFB85609F67E529A0383DB0C4BC00645EAE3AD1CBDE6F91091400AB02508D332E003516EF7C07A9769827621900E9D86F0DE75500E2E44E213EEEE8970A5FBEC82F799A2E190D0B483B96EA87410DFF5B9FDBA2D7EFD0E37FF7CEE237BE6E9FCFB331B4EB12C30A2CE7FFE0E10A2EA200D458BC87D3834065EF236605A01AE75A005200040355F38B135B36C2F0FA6EB0A49038D302302CDC2B8EFD73D2E79CD92580D5FEA5D03098EC8A2AFE0F8B739AFCCB93767ABCDBBD7EF96428FFBCBC64D4A38AFF7948177EAFBA0420BC1F3EE76C0A402A82470678DA3418947D85D9FC1FC6C4892736E973CEED1240CAEB90DF6A7EC71C90F33EBCBE2B7F2BC7CF11D814803EC087C57D4501488F7793BEEE915F8949000C8BFFE9E6E5BB088B5D81E50EA0DBBDAD2B00E77702D079B41CDC6942178B780AFC1D056F3C31A81F0675FCEF8FFED37CCE767E8AE9BCCF4E0D666463C7685CD81580B2EC1D483F1ECEFA046058FC4FDFBCE52740169950DDFFDEBF61715F5100D2E3DDBCAF5FFA132605201996CC5A5AE80F2900E9B3E4EB2A517D000C8B7F6D6C06826501587D39C8A8ED2B6AF9DF86BD5AC4C5789884FBBEE75BBAF22003E3446AF99FCA7AFAFFF36F2976EB4B85BE7D5CBE367D4EFF8B640CC6856501587D1C6C74DAA7A83EFF87C5BF36361BC1DAFEA70D5B9AC34B0BFD2105207D96C5BC8FD42F007B9AFF7AEC4E01AA0E80B49BB3E0EC2E014416767743902F14848D8EFF23D5FCEF17F261B20E0B7B51DCFAC7DB80C8FF9C9E1FC6D0F8BE32546A52CDFFD9DC2F777FD958C8FD4DEF9B2DEEE5D8388F0560CA783FC884612E2F14848D8EFF2355E7BF59FE07CEE1128059FEDB6CFEAA1780D4DA6BEED8872320A345A1DE004893B9B6596388583441D302B0B81BE81787C5E76D2FFBE4D4F1BFF37EF87F84EC595CB097CA817C4DFFBA47F1EF37F512403F4FFB90EEE66C5E000E3D09CA7D9F5E5688D9721647C039130F737A1F179FB7097C45BDF99F3CAE3D77C7E26871125CD3FF74A9AE664EA7F26F510AEB1680C5267F2A5603ABA3D60030BD5E3334CB9BBB00CCD9751360EFA92A7566E34853C5FF18E4FDAEAE9DB0079CD6C4F1B23F2852B188AF8B45B0FEF8AAE57F5CA087805E28763B037CE13DFB2E259E8A5D0148C55DCDD97EB3A0423DCDF58D2E03D4F4DFACB80F270BA7DF535052CD7F33DFAC3696950BC078CDAEF220C88F950C4E01AA0C00C305BA230D82FAC7C07605E0D05DDF02675C000ED9011C5600F2D7DDFC0290E6E7C95920E6FCA46054C4AE008C737615E754000C17E88E314B6EEA4DA069F75F7DA1CE2F2B543E05A858004E0CFB83B9990D7038A6D982CAC1B02A008EBCD1E798E01E2EF91CC8A98150AF00C6F2D7EDFA64495B3CEEED5998DCC38942FB6FDCDC023059B40355827A32CE6C169755FEEFF3B2E090A29738364B4EDD10D4F0FFD8397B12953706750AC08965EF60EA6E30EB1500EB06387C7EFD23A6D307C0788D7E1BEA0E82B501D0EEF236DAA5CFE92F2F543811AA13005970670B7919E6BB1682710751BE761C5FC72C248752AD0004BA9D7F31478F2C8B914979E8E7BEC5EE3FB2D6FFD6AF8D76E973FA3151614778BAFF0B37FA9A51778DA932FFAD4F8087CFAFBB01389F0260781F40BD02507F7736C16890AD0E8036D8D7F85D9E16ADF1B4FB8C1ABBCC5A052032ECD6C39F4F5A2092D76DC077BB0B8BC53F52AF0014F77CACD9BDCB53847A654FB1DAFFF61460CD5C2C778B6B72A3FB8C1A9703EB1580FAD93CC1688D398B02308C991B5F008C06C1102637B100D89833E3A841F6B879F5E547CDABE7EAB929AB03A0F5FC383F866BC35998ABC7F6D28FB79B5600A6A741278E87C1EF408D9DE6CB07CD8B2FEF36AF5F4E1FAF5700322F0756867551042237ED04A0F3E7388F87539E6CE7AE1EDB4B3F368E2D00EF9EDC1DBE77CA86D3FDB7DB9C4D388B0260B4060C979C0EFDFCC3F27F4701E882E2EDC3F2F105C484B5E1261780AD38BF02302E0C0BAFCFC7CF2145E0887F7B1F750B40477E9CBF6A97962FFE158E795B362800F3D39DB5615D7C8EE1A5A62D0AC0381E165E7FACDF47FCDB235D26BC78F26CF278BD02B01537B90058B35101486F3CB80004B6B811E466DE05ECB900A8FF3EC111013EDF452E71730BC0C091378BE5D438DE9DB04901E8A89905556E26DCC1690540FF37CF38E204272F8FBB595700CA4CA000D499FFC7DEBCB986C32F03AE2E00DF346FE3932F9F35EFC2FF1E53006E1EFD77C979FECDEC75A60BC0B5D10F802731F43F1ABEAB1A10160BC04D62FA9DA32ED3E72FD3FF483706061DDAB1B04D0198714459ACB9E04FBD7FD6BCBE9ABFE672FDCF68CBDF3816FE72F5A0CDF7F8DCE5CEFF69FEBF0DE3FF9D18039EF37F5E001E3EEE17C94EBCF32D007DD0E50B7EFC6EE23B5DF2001874888FF521500E82CB0D80FEBBB7DFBB7BACFDEED9DF2397E97F0CBAFCB8578C879ECBF47F69FE7B590014FDA2E062FE97FEA732E0AB004C4A50ABC574FEEFB807E0DC0B80427FA74B1E00E5F5BEF626A0ACFD472EB600B4DFB398F0FD77CFC7C045FA9F95F8E9634E0A40EB739C03D3C7DBC52F2F05010AC005FADF96BDC27F570550E5FFDCFF8B2F00E50218F15300E661AF16868B2D002A040497E8BF2A7A5BDE0370EDF4A77D120AC0E4F14BF4BFCDFDE2A44F6E0802975C00A65EBB2A0029E872C3BD9D0050002800D9E38E0A4057FCF77B1FA1005000723D2E03E5F5FCB1CB2D00CAEC3E10FD1480F964777F09408CEB8BF45F14BDEE314F2700F3B05750002ED5FFF87DCBC728003E0A40FFDF3FFEE28B31F83C1580C922D01F7DBA088096DEF36C27A0768697E97F0CBAE0FF7014DEFFDD4B0110DECF33A1830270C1FE0F977B520E52009C1480C0107E1D6F1F9683A2E3A207003F062826C1F4F9CB5D00D2A2DFEB709D3F06782DCCBF6BB9F847280097EA7FB6F909B8FC3140D705E040FC0480E6D20BC03EF01FFF952E5E70E3BFBA2C10F0ECFF8E02E00702800540E9E205FCC77FA5CB5933BBDEAF4F7F2314000A8014C70B2C00F8AF74F102FE5FA6FFB31F01178B7F8402400190E278810500FF952E5EC07FFC57BA5C3EBF34FF1FEE9E7797685376210000000049454E44AE426082)
OnClick: Local turn := cur_turn;~
~
DeferWindowsResynch(~
Local sq := xy_to_square(click_x, click_y, View_perspective );~
if Selected_square = sq then (~
Selected_square := null~
) else if Selected_square = null then (~
Local pc := Get_piece_at( Current_board_state, sq );~
if pc <> null and SelectText(pc,1,1)=turn then ~
Selected_square := sq~
) else (~
Local from:=Selected_square, to:=sq;~
~
Local (newBs, valid) := Try_move( Current_board_state, from, to );~
if valid then (~
Current_board_state := newBs;~
Prev_move_from := from;~
Prev_move_to := to;~
) else (~
MsgBox( f"Invalid move", buttons:0 );~
);~
Selected_square := null;~
);~
Refresh_board_image~
);~
~
if turn<>cur_turn then ~
Maybe_automove
Button Reset_to_start
Title: Reset to start
NodeLocation: 200,620,1
NodeSize: 64,20
WindState: 2,98,82,847,451
OnClick: Reset_to_start_witho;~
Maybe_automove
Button Flip_perspective
Title: ↺
NodeLocation: 92,620,1
NodeSize: 28,20
NodeInfo: 1,,,,,,1
NodeFont: Arial,32
OnClick: View_perspective := if View_perspective='B' then 'W' else 'B';~
Refresh_board_image
Button Refresh_board_image
Title: Refresh board image
NodeLocation: 280,796,1
NodeSize: 64,28
WindState: 2,574,61,720,553
OnClick: pict of Boardimage := Draw_board(Current_board_state, View_perspective, highlightColors:Highlight_colors );~
Mid(FEN_of_current_posit);~
Mid(Who_s_turn_);~
if game_over then (~
DeferWindowsResynch(true); { pump windows msg queue }~
if Is_in_check(cur_board, cur_turn) then ~
MsgBox(f"Checkmate. {if cur_turn='W' then 'Black' else 'White'} wins!", buttons:0, title:"Game over")~
else~
Msgbox(f"Stalemate. ½-½", buttons:0, title:"Game over")~
);~
DeferWindowsResynch(true) { pump windows msg queue }
FormNode Fo1164481619
Title: FEN of current position
Definition: 1
NodeLocation: 568,724,1
NodeSize: 496,20
NodeInfo: 1,,,,,,,808,,,,,,0
Original: FEN_of_current_posit
Button Let_GPT_move
Title: Let GPT move
NodeLocation: 344,620,1
NodeSize: 64,20
WindState: 2,98,82,1299,677
OnClick: Selected_square := null;~
ShowProgressBar("GPT is thinking...", "Waiting for GPT to make a move...", 0.5);~
EvaluateScript("ResynchAllWindows"); { To avoid a partial repaint while GPT thinks}~
if invalidate_next_time then InvalidateResult(GPT_response);~
invalidate_next_time := false;~
GPT_s_previous_respo := GPT_response;~
ShowProgressBar("GPT is thinking...", "Waiting for GPT to make a move...", 0.99); ~
~
if Is_GPT_move_legal_ then (~
Prev_move_from := GPT_move[from_to='from'];~
Prev_move_to := GPT_move[from_to='to'];~
) else~
Prev_move_to := Prev_move_from := null;~
~
if Is_GPT_move_legal_ then ~
Current_board_state := Board_state_after_GP~
else (~
invalidate_next_time := true;~
MsgBox(description_of_illeg);~
);~
~
Refresh_board_image;~
~
ShowProgressBar("GPT is thinking...", "Waiting for GPT to make a move...", 1.1); { remove progress }
FormNode Fo243045459
Title: Turn text
Definition: 1
NodeLocation: 168,48,1
NodeSize: 112,16
NodeInfo: 1,,,,,,,120,,,,,,0
Original: Who_s_turn_
FormNode Fo751473747
Title: GPT auto move
Definition: 0
NodeLocation: 436,48,1
NodeSize: 148,16
NodeInfo: 1,,,,,,,160,,,,,,0
Original: GPT_auto_move
Module Implementation
Title: Implementation
Author: Lonnie Chrisman~
Lumina Decision Systems
Date: Thu, Sep 28, 2023 9:18 AM
NodeLocation: 120,792,1
NodeSize: 72,24
NodeInfo: ,,,,,,,,,,,4
DiagState: 2,732,105,2404,816,17,10
Library Chess_library
Title: Chess library
Author: Lonnie Chrisman~
Lumina Decision Systems
Date: Tue, Sep 26, 2023 10:16 AM
NodeLocation: 112,56,1
NodeSize: 64,24
NodeInfo: 1,,0,,,,,0,,,0,,,0
DiagState: 2,12,14,1351,658,17,10
Index Rank1
Title: Rank
Definition: Sequence(8,1)
NodeLocation: 128,64,1
NodeSize: 64,24
Index File
Title: File
Definition: 'a'..'h'
NodeLocation: 128,120,1
NodeSize: 64,24
Index Board_state_rec
Att_PrevIndexValue: ['rBoard','Turn','W can castle Qside','W can castle Kside','B can castle Qside','B can castle Kside','En passant square','Halfmoves','Fullmoves']
Title: Board state rec
Definition: ['rBoard','Turn','W can castle Qside','W can castle Kside','B can castle Qside','B can castle Kside','En passant square','Halfmoves','Fullmoves']
NodeLocation: 128,184,1
NodeSize: 64,24
Function Parse_FEN( fen : text atom )
Title: Parse FEN
Description: Parses a Forsyth-Edwards Notation (FEN) string and returns a board state.
Definition: Local rankFen := ~
SplitText(FindInText("^[rnbqkp12345678/]+", fen, caseInsensitive:true, re:true, return:'S'),~
'/',resultindex:Rank1);~
for i:=1..8 do ~
rankFen := TextReplace(rankFen,f"{i:I}",SelectText('--------',1,i));~
Local board := FEN_letter_to_piece[FEN_letter_to_piece=SplitText(rankFen, '', resultindex:File )];~
Local state := null;~
~
Local parts := SplitText(fen,'\s+',re:true);~
~
state[Board_state_rec='rBoard'] := \board;~
state[Board_state_rec='Turn'] := if Slice(parts,2)='b' then 'B' else 'W';~
state[Board_state_rec='W can castle Kside'] := FindInText('K',Slice(parts,3),caseInsensitive:false)>0;~
state[Board_state_rec='W can castle Qside'] := FindInText('Q',Slice(parts,3),caseInsensitive:false)>0;~
state[Board_state_rec='B can castle Kside'] := FindInText('k',Slice(parts,3),caseInsensitive:false)>0;~
state[Board_state_rec='B can castle Qside'] := FindInText('q',Slice(parts,3),caseInsensitive:false)>0;~
state[Board_state_rec='En passant square'] := null;~
state[Board_state_rec='Halfmoves'] := ParseNumber(Slice(parts,5),0);~
state[Board_state_rec='Fullmoves'] := ParseNumber(Slice(parts,6),1);~
state
NodeLocation: 120,304,1
NodeSize: 64,24
WindState: 2,595,360,1456,720
Constant FEN_letter_to_piece
Att_PrevIndexValue: ['-','r','R','n','N','b','B','q','Q','k','K','p','P']
Title: FEN letter to piece
Definition: Table(Self)(Null,'BR','WR','BN','WN','BB','WB','BQ','WQ','BK','WK','BP','WP')
IndexVals: ['-','r','R','n','N','b','B','q','Q','k','K','p','P']
NodeLocation: 480,64,1
NodeSize: 64,24
DefnState: 2,116,122,462,454,0,DFNM
ReformDef: [Undefined,Self]
{!40700|Att_CellFormat: CellEntry(0,0,1,1,0)}
Function Draw_board( boardState : [Board_state_rec] ; ~
perspective : text atom = 'W' ; ~
w,h : positive atom = 512 ;~
darkSquareColor : color atom = 0xab4421 ;~
lightSquareColor : color atom = 0xfad8b4 ;~
highlightColors : color orNull [ Rank1, File ] = Null~
)
Title: Draw board
Description: Returns an image of the chess board state.~
~
«boardState»: A board state representation.~
«perspective»: Either 'W' or 'B' -- which side is the board viewed from?~
«w»,«h»: Size of the board in pixels.~
Definition: Local r:=If perspective='B' then Rank1 else 9-Rank1;~
Local f:=If perspective='B' then 9-@File else @File;~
Local r_bot := If perspective='B' then 1 else 8;~
Local f_left := if perspective='B' then 1 else 8;~
Local x:=(f-1)*(w/8)+1, y:=(r-1)*(h/8)+1;~
Local x_left := 1, y_bot := 7*(h/8);~
Local pieceFontSz := 30 * Min([w,h])/512;~
Local canv := Canvas(w,h,lightSquareColor);~
{ Draw the squares }~
Local squareColor := if Mod(r+f,2) then darkSquareColor else lightSquareColor; ~
CanvasDrawRectangle( canv, x, y, w/8, h/8, fillColor:squareColor);~
{ Draw the highlight colors }~
CanvasDrawRectangle( canv, x, y, w/8, h/8, fillColor:highlightColors);~
{ Draw the rank & file markings }~
CanvasDrawText(canv, File, x+(w/8), y_bot+h/8, hAlign:'Right',vAlign:'Bottom', color:squareColor[Rank1=r_bot]);~
CanvasDrawText(canv, f"{Rank1:I}", x_left, y+h/8, hAlign:'Left',vAlign:'Bottom', color:squareColor[@File=f_left]);~
{ Draw the pieces }~
Local board := #boardState[Board_state_rec='rBoard'];~
Local c := Piece_char[Piece=board];~
~
CanvasDrawText( canv, c, x+w/16, y+h/8, font:'Arial', hAlign:'Center', vAlign:'Bottom', color:'black', fontSize:pieceFontSz );~
CanvasImage(canv)
NodeLocation: 120,472,1
NodeSize: 64,24
WindState: 2,16,-19,1202,828
Index Piece
Title: Piece
Definition: ['WR','WN','WB','WQ','WK','WP','BR','BN','BB','BQ','BK','BP']
NodeLocation: 640,64,1
NodeSize: 64,24
Constant Piece_char
Title: Piece char
Definition: Table(Piece)('♖','♘','♗','♕','♔','♙','♜','♞','♝','♛','♚','♟')
NodeLocation: 640,128,1
NodeSize: 64,24
DefnState: 2,183,89,620,512,0,DFNM
ValueState: 2,212,218,706,710,,MIDM
{!40700|Att_CellFormat: CellFormats(CellEntry(0,0,1,0,0),CellFont('Arial',72))}
Variable Empty_board
Title: Empty board
Definition: Table(Board_state_rec)(\null,'W',1,0,0,1,Null,0,1)
NodeLocation: 848,64,1
NodeSize: 64,24
Variable Empty_board_image
Title: Empty board image
Definition: Draw_board(Empty_board)
NodeLocation: 848,144,1
NodeSize: 64,24
ValueState: 2,1118,274,769,645,,MIDM
Variable Starting_board
Title: Starting board
Definition: Parse_FEN('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1')
NodeLocation: 1008,64,1
NodeSize: 64,24
Function xy_to_square( x,y : atom nonNegative ;~
perspective : atom text ; ~
w,h : positive atom = 512~
)
Title: xy to square
Description: Maps a pixel location in a board image to the board square at that position.
Definition: Local f := Ceil(x/(w/8));~
Local r := Ceil(y/(h/8));~
f := if perspective='W' then f else 9-f;~
r := if perspective='W' then r else 9-r;~
f"{File[@File=f]}{Rank1[@Rank1=r]:I}"
NodeLocation: 448,304,1
NodeSize: 64,24
WindState: 2,2434,539,720,513
Function Get_piece_at( boardState : [Board_state_rec] ; square : text atom )
Title: Get piece at
Description: «square» must be a 2-char square name such as 'e7'
Definition: Piece_at( #boardState[Board_state_rec='rBoard'], square )~
NodeLocation: 280,584,1
NodeSize: 64,24
WindState: 2,1002,698,720,350
Function Square_to_grid( square : text atom ; onSquareValue, offSquareValue : atom = null )
Title: Square to grid
Description: Returns a 2-D board matrix with then «onSquareValue» at the indicated «square», and the «offSquareValue» on all other squares.
Definition: if SelectText(square,1,1)=File and SelectText(square,2,2)=f"{Rank1:I}" then~
onSquareValue~
else~
offSquareValue
NodeLocation: 112,688,1
NodeSize: 64,24
WindState: 2,98,82,965,493
Function Try_move( boardState : [Board_state_rec] ; ~
fromSquare, toSquare : text atom ; ~
promoteTo : text atom = 'Q' )
Title: Try move
Description: Returns False as the second return value if the move is not legal and leaves boardState unchanged in that case. If valid, moves the piece. Handles en passant, castle and promotion and check to the king.
Definition: Local pc : Get_piece_at(boardState, fromSquare);~
Local turn := boardState[Board_state_rec='Turn'];~
Local captured := Get_piece_at(boardState, toSquare);~
Local (c,ty) := Piece_to_color_type(pc);~
Local selfCapture := captured<>null and Piece_to_color_type(captured)=c;~
~
if pc=null or c<>turn or selfCapture or fromSquare=toSquare then _(boardState,false) else begin~
Local (newState, valid ) := ~
if ty='P' then ~
Try_Pawn_Move( boardState, fromSquare, toSquare, promoteTo )~
else if ty='R' then~
Try_Rook_move( boardState, fromSquare, toSquare )~
else if ty='N' then~
Try_Knight_move( boardState, fromSquare, toSquare )~
else if ty='B' then~
Try_Bishop_move( boardState, fromSquare, toSquare )~
else if ty='Q' then ~
Try_Queen_move( boardState, fromSquare, toSquare )~
else if ty='K' then~
Try_King_move( boardState, fromSquare, toSquare )~
else ~
_(boardState,false);~
~
if not valid or Is_in_check(#newState[Board_state_rec='rBoard'], c) then~
_( boardState, false ) { Cannot move into check }~
else~
_( newState, true )~
end
NodeLocation: 280,304,1
NodeSize: 64,24
WindState: 2,760,171,955,914
Function square_to_file_rank( square : text atom )
Title: square to file rank
Description: Returns the file (as a letter) and rank of the given square. These are returned as two return values.
Definition: _( SelectText(square,1,1), ParseNumber(SelectText(square,2,2)) )
NodeLocation: 704,304,1
NodeSize: 64,24
Function Piece_to_color_type( piece : text atom )
Title: Piece to color type
Definition: _( selectText(piece,1,1), selectText(piece,2,2) )
NodeLocation: 280,640,1
NodeSize: 64,24
WindState: 2,479,490,720,350
Function square_to_coord( square : text atom )
Title: square to coord
Description: Returns the file number (number) and rank of the given square. They are returned as separate return values.
Definition: _( @[File=SelectText(square,1,1)], ParseNumber(SelectText(square,2,2)) )
NodeLocation: 704,360,1
NodeSize: 64,24
WindState: 2,101,470,832,550
Function coord_to_square( file_num, rank : number atom )
Title: coord to square
Description: Returns a square designator such as 'd6' from the file number (1..8) and rank.
Definition: if file_num<1 or file_num>8 or rank<1 or rank>8 then null else f"{File[@File=file_num]}{rank:I}"
NodeLocation: 704,416,1
NodeSize: 64,24
WindState: 2,276,629,720,350
Function Set_square( boardState : [Board_state_rec] ; ~
square: text atom ; ~
piece : text orNull atom~
)
Title: Set square
Description: Sets the indicated square to piece and returns the updated state. No other aspect of the state is altered.
Definition: Local board := #boardState[Board_state_rec='rBoard'];~
Local (f, r) := square_to_file_rank(square);~
Local newBoard := if File=f and Rank1=r then piece else board;~
~
if Board_state_rec='rBoard' then \newBoard else boardState
NodeLocation: 112,744,1
NodeSize: 64,24
WindState: 2,628,240,823,485
Function Attackers( board : [File, Rank1] ;~
fileNum, rank : positive atom ;~
attackerColor : text atom ;~
returnNullIfNone : boolean atom = true~
)
Title: Attackers
Description: Returns the set of squares containing attackers of the indicated square.
Definition: ToSet(#SetUnion( [~
Diagonal_attackers( board, fileNum, rank, attackerColor),~
Straight_attackers( board, fileNum, rank, attackerColor ),~
Pawn_attackers( board, fileNum, rank, attackerColor ),~
Knight_attackers( board, fileNum, rank, attackerColor ),~
King_attacker( board, fileNum, rank, attackerColor )~
]))
NodeLocation: 280,360,1
NodeSize: 64,24
WindState: 2,1732,285,830,737
Constant Piece_name
Title: Piece name
Definition: Table(Piece)('white rook','white knight','white bishop','white queen','white king','white pawn','black rook','black knight','black bishop','black queen','black king','black pawn')
NodeLocation: 480,136,1
NodeSize: 64,24
{!40700|Att_CellFormat: CellEntry(0,0,1,0,0)}
Function Piece_at( board : [File, Rank1] ; square : text atom )
Title: Piece at
Description: «square» must be a 2-char square name such as 'e7'
Definition: Local (f,r) := square_to_file_rank(square);~
board[ File=f, Rank1=r ]
NodeLocation: 280,528,1
NodeSize: 64,24
WindState: 2,1002,698,720,350
Constant Square_names
Title: Square names
Definition: File&Rank1
NodeLocation: 1016,144,1
NodeSize: 64,24
ReformVal: [File,Rank1]
Index Piece_type
Title: Piece type
Definition: ['R','N','B','Q','K','P']
NodeLocation: 312,128,1
NodeSize: 64,24
Constant Piece_type_name
Title: Piece type name
Definition: Table(Piece_type)('rook','knight','bishop','queen','king','pawn')
NodeLocation: 320,184,1
NodeSize: 64,24
{!40700|Att_CellFormat: CellEntry(0,0,1,0,0)}
Function Piece_type_counts( board : [File, Rank1] ;~
color : text atom)
Title: Piece type counts
Description: Returns a 1-D array indexed by Piece_type containing the number of pieces of each type on the board with the given color.
Definition: Local (c,ty) := Piece_to_color_type(board);~
Sum( c=color and ty=Piece_type, File, Rank1)
NodeLocation: 280,752,1
NodeSize: 64,24
WindState: 2,1343,331,720,350
Function Avail_moves_for( boardState : [Board_state_rec] ;~
square : text atom ~
)
Title: Avail moves for
Description: Returns the set of possible moves for the piece at the indicated square, or null if there isn't a piece on that square or there are no possible moves.
Definition: Local pc := Get_piece_at(boardState, square);~
Local (c,ty) := Piece_to_color_type(pc);~
~
Local candidates := ~
if ty='R' then Rook_move_candidates( square )~
else if ty='N' then Knight_move_candidat( square )~
else if ty='B' then Bishop_move_candidat( square )~
else if ty='Q' then Queen_move_candidate( square )~
else if ty='K' then King_move_candidates( square )~
else if ty='P' then Pawn_move_candidates( square, c )~
else null;~
~
if IsNull(candidates) then null else ~
Legal_moves_from_can(boardState, square, candidates)~
NodeLocation: 280,416,1
NodeSize: 64,24
WindState: 2,2149,28,720,350
Function Avail_moves( boardState : [board_state_rec] )
Title: Avail moves
Description: Returns the set of available moves for the current turn. Returns Null if currently mated or stalemated. ~
~
The available moves are expressed as the square that the piece ends up in (i.e., not PEN notation).
Definition: {Local board := #boardState[Board_state_rec='rBoard'];~
Local turn := boardState[Board_state_rec='Turn'];~
Local moveSets := ~
Local (c[],ty[]) := Piece_to_color_type( board ) Do~
if c=turn then Avail_moves_for(boardState,square_names) else null;~
Local moves := SetUnion(SetUnion( moveSets, File ), Rank1 );~
ToSet(#moves);}~
~
avail_moves_for( boardState, square_names )
NodeLocation: 280,472,1
NodeSize: 64,24
WindState: 2,2153,437,720,350
Function Color_at_coord( board : [File, Rank1 ] ;~
fileNum, rank : number atom )
Title: Color at coord
Description: The color of the piece at the given board position, with numeric file number.
Definition: Piece_to_color_type( board[@File=fileNum, Rank1=rank] )
NodeLocation: 704,480,1
NodeSize: 64,24
Function Is_piece_at_square( boardState : [Board_state_rec];~
square : text atom ;~
piece : text atom )
Title: Is piece at square
Description: Returns true if piece is at square.
Definition: Local board:=#boardState[Board_state_rec='rBoard'];~
Piece_at(board, square) = piece
NodeLocation: 112,808,1
NodeSize: 64,24
Index from_to
Title: from to
Definition: ['from','to']
NodeLocation: 312,64,1
NodeSize: 64,24
Function FEN_string( boardState : [Board_state_rec] )
Title: FEN string
Description: Returns the FEN string for the board state.
Definition: Local board := #boardState[Board_state_rec='rBoard'];~
Local cumNullCount := Cumulate( board=null, File, reset: board<>null );~
Local boardEncoding := ~
JoinText(JoinText(~
if cumNullCount=0 then ~
Local (c,ty) := Piece_to_color_type(board) Do~
if c='B' then TextLowerCase(ty) else ty~
else if cumNullCount[@File=@File+1]>0 then null~
else cumNullCount,~
File),Rank1,'/');~
~
Local turn := TextLowerCase(boardState[Board_state_rec='Turn']);~
~
LocalIndex CastleRightField := ['W can castle Kside','W can castle Qside','B can castle Kside','B can castle Qside'];~
Local hasRight := boardState[Board_state_rec=CastleRightField];~
Local rightTxt := Array(CastleRightField,['K','Q','k','q']);~
Local castleChars := JoinText(if hasRight then rightTxt else '', CastleRightField);~
Local castleRights := if castleChars='' then '-' else castleChars;~
~
Local enPassantSq := boardState[Board_state_rec='En passant square'];~
enPassantSq := if enPassantSq=null then '-' else enPassantSq;~
~
Local halfMoveClock := boardState[Board_state_rec='Halfmoves'];~
Local fullMoveClock := boardState[Board_state_rec='Fullmoves'];~
~
f"{boardEncoding} {turn} {castleRights} {enPassantSq} {halfMoveClock:I} {fullMoveClock:I}"
NodeLocation: 120,360,1
NodeSize: 64,24
WindState: 2,2270,46,858,737
Module Chess_helper_functio
Title: Chess helper functions
Author: Lonnie Chrisman~
Lumina Decision Systems
Date: Thu, Oct 5, 2023 8:55 AM
NodeLocation: 1184,72,1
NodeSize: 64,24
DiagState: 2,12,68,1373,645,17,10
Function Try_pawn_move( boardState : [Board_state_rec] ; ~
fromSquare, toSquare : text atom ; ~
promoteTo : text atom = 'Q' )
Title: Try pawn move
Description: Attempts a pawn move. Caller must already ensure that the fromSquare has pawn. Returns:~
1. Updated board state (if legal)~
2. True if legal, false if not~
~
Handles captures, en passant, and promotions.
Definition: Local turn := boardState[Board_state_rec='Turn'];~
Local rankDir := if turn='W' then 1 else -1;~
Local backRank := if turn='W' then 8 else 1;~
Local startRank := if turn='W' then 2 else 7;~
Local board := #boardState[Board_state_rec='rBoard'];~
Local pc := Get_piece_at(boardState, fromSquare);~
~
Local (f_from, r_from) := square_to_coord(fromSquare);~
Local (f_to, r_to ) := square_to_coord(toSquare);~
~
if sign(r_to-r_from)<>rankDir then (~
_(boardState,false)~
) else if abs(r_to-r_from)=2 and r_from=startRank then (~
if f_to<>f_from or board[@File=f_to,Rank1=r_from+rankDir]<>null or board[@File=f_to,Rank1=r_from+2*rankDir]<>null then~
_(boardState,false)~
else { valid starting move, forward 2 squares }~
_( Basic_move( boardState, fromSquare, toSquare, pc, ~
enPassantSquare: coord_to_square( f_from, (r_to+r_from)/2 ) ), true )~
) else if r_to-r_from<>rankDir or abs(f_to-f_from)>1 then (~
_( boardState, false )~
) else if abs(f_to-f_from)=1 then ( ~
if toSquare=boardState[Board_state_rec='En passant square'] then ~
{ en passant }~
Local newState1 := basic_move( boardState, fromSquare, toSquare, pc ) Do~
_( Set_square( newState1, coord_to_square(f_to, r_from), null ), true )~
else ~
{ should be a capture }~
Local captured := Get_piece_at(boardState,toSquare);~
if captured=null or Piece_to_color_type(captured)=Piece_to_color_type(pc) then ~
_(boardState, false ) ~
else { valid capture }~
basic_move( boardState, fromSquare, toSquare, if r_to=backRank then turn&promoteTo else pc)~
) else if (board[@File=f_to,Rank1=r_from+rankDir]<>null) then (~
{ piece blocks simple move }~
_( boardState, false )~
) else ( { simple move }~
_( basic_move( boardState, fromSquare, toSquare, if r_to=backRank then turn&promoteTo else pc ), true )~
)~
~
~
NodeLocation: 592,64,1
NodeSize: 64,24
WindState: 2,1311,-3,1149,1107
Function basic_move( boardState : [Board_state_rec] ; ~
fromSquare, toSquare : text atom ;~
piece : text atom ;~
enPassantSquare : text orNull atom = null;~
removeCastleOptQside : boolean atom = false ;~
removeCastleOptKside : boolean atom = false~
)
Title: basic move
Description: No checking for validity. Puts the piece currently at fromSquare at toSquare and clears fromSquare. Returns the new board state.
Definition: Local board := #boardState[Board_state_rec='rBoard'];~
Local (f_from, r_from) := square_to_coord(fromSquare);~
Local (f_to, r_to ) := square_to_coord(toSquare);~
Local turn := boardState[Board_state_rec='Turn'];~
~
Local newBoard :=~
if @File=f_to and Rank1=r_to then piece~
else if @File=f_from and Rank1=r_from then Null~
else board;~
~
if Board_state_rec='rBoard' then~
\newBoard~
else if Board_state_rec='En passant square' then ~
enPassantSquare~
else if Board_state_rec='Turn' then ~
if turn='W' then 'B' else 'W'~
else if Board_state_rec=(turn&' can castle Kside') and removeCastleOptKside then~
False~
else if Board_state_rec=(turn&' can castle Qside') and removeCastleOptQside then~
False~
else if Board_state_rec='Fullmoves' and turn='B' then~
boardState[Board_state_rec='Fullmoves']+1~
else~
boardState
NodeLocation: 440,176,1
NodeSize: 64,24
WindState: 2,281,79,1101,979
Function Try_Knight_move( boardState : [Board_state_rec] ; ~
fromSquare, toSquare : text atom~
)
Title: Try Knight move
Description: Attempts a knight move. Returns two results:~
1. Updated board state (if legal)~
2. True if legal, false if not~
~
Caller should have validated that the knight is on the fromSquare and of the same color al the current Turn.
Definition: Local turn := boardState[Board_state_rec='Turn'];~
Local board := #boardState[Board_state_rec='rBoard'];~
Local pc := Get_piece_at(boardState, fromSquare);~
~
Local (f_from, r_from) := square_to_coord(fromSquare);~
Local (f_to, r_to ) := square_to_coord(toSquare);~
~
if abs(abs(f_from-f_to)-abs(r_from-r_to))<>1 then { Not an L move }~
_(boardState,false) ~
else { legal }~
_( basic_move( boardState, fromSquare, toSquare, pc ), true )
NodeLocation: 592,176,1
NodeSize: 64,24
WindState: 2,418,113,737,471
Function Try_Bishop_move( boardState : [Board_state_rec] ; ~
fromSquare, toSquare : text atom~
)
Title: Try Bishop move
Description: Attempts a knight move. Returns two results:~
1. Updated board state (if legal)~
2. True if legal, false if not~
~
Caller should have validated that the knight is on the fromSquare and of the same color al the current Turn.
Definition: Local turn := boardState[Board_state_rec='Turn'];~
Local board := #boardState[Board_state_rec='rBoard'];~
Local pc := Get_piece_at(boardState, fromSquare);~
~
Local (f_from, r_from) := square_to_coord(fromSquare);~
Local (f_to, r_to ) := square_to_coord(toSquare);~
~
if abs(f_from-f_to)<>abs(r_from-r_to) then { Move is not on the diagonal }~
_(boardState,false)~
else if Is_clear_path_betwee( board, f_from, r_from, f_to, r_to ) then~
{legal }~
_( basic_move( boardState, fromSquare, toSquare, pc ), true )~
else ~
{ blocked }~
_( boardState, false )
NodeLocation: 592,232,1
NodeSize: 64,24
WindState: 2,178,124,782,839
Function Try_Rook_move( boardState : [Board_state_rec] ; ~
fromSquare, toSquare : text atom~
)
Title: Try Rook move
Description: Attempts a knight move. Returns two results:~
1. Updated board state (if legal)~
2. True if legal, false if not~
~
Caller should have validated that the knight is on the fromSquare and of the same color al the current Turn.
Definition: Local turn := boardState[Board_state_rec='Turn'];~
Local board := #boardState[Board_state_rec='rBoard'];~
Local pc := Get_piece_at(boardState, fromSquare);~
~
Local (f_from, r_from) := square_to_coord(fromSquare);~
Local (f_to, r_to ) := square_to_coord(toSquare);~
~
if (f_from=f_to or r_from=r_to) and ~
Is_clear_path_betwee( board, f_from, r_from, f_to, r_to ) then~
{legal }~
_( basic_move( boardState, fromSquare, toSquare, pc, ~
removeCastleOptKside:f_from=8, removeCastleOptQside:f_from=1 ),~
true )~
else ~
{ blocked or wrong dir }~
_( boardState, false )
NodeLocation: 592,120,1
NodeSize: 64,24
WindState: 2,2223,86,782,903
Function Try_Queen_move( boardState : [Board_state_rec] ; ~
fromSquare, toSquare : text atom~
)
Title: Try Queen move
Description: Attempts a knight move. Returns two results:~
1. Updated board state (if legal)~
2. True if legal, false if not~
~
Caller should have validated that the knight is on the fromSquare and of the same color al the current Turn.
Definition: Local turn := boardState[Board_state_rec='Turn'];~
Local board := #boardState[Board_state_rec='rBoard'];~
Local pc := Get_piece_at(boardState, fromSquare);~
~
Local (f_from, r_from) := square_to_coord(fromSquare);~
Local (f_to, r_to ) := square_to_coord(toSquare);~
~
if (f_from=f_to or r_from=r_to or abs(f_from-f_to)=abs(r_from-r_to)) and ~
Is_clear_path_betwee( board, f_from, r_from, f_to, r_to ) then~
{legal }~
_( basic_move( boardState, fromSquare, toSquare, pc ), true )~
else ~
{ blocked or wrong dir }~
_( boardState, false )
NodeLocation: 592,296,1
NodeSize: 64,24
WindState: 2,155,13,782,960
Function Try_King_move( boardState : [Board_state_rec] ; ~
fromSquare, toSquare : text atom~
)
Title: Try King move
Description: Attempts a King move. Returns two results:~
1. Updated board state (if legal)~
2. True if legal, false if not~
~
Handles castling. Does not prevent moving into check -- that is done at the caller's level.~
~
Definition: Local turn := boardState[Board_state_rec='Turn'];~
Local board := #boardState[Board_state_rec='rBoard'];~
Local pc := Get_piece_at(boardState, fromSquare);~
Local backRank := if turn='W' then 1 else 8;~
~
Local (f_from, r_from) := square_to_coord(fromSquare);~
Local (f_to, r_to ) := square_to_coord(toSquare);~
~
Local castleSide := if f_to<4 then "K" else "Q";~
~
if f_from=5 and abs(f_from-f_to)=2 and r_from=r_to and r_from=backRank ~
and boardState[Board_state_rec=f"{turn} can castle {castleSide}side"]~
then (~
{ Attempted castle }~
Local rookFile := if f_to turn or rookTy<>'R' then { Rook not in corner}~
_( boardState, false )~
else if not Is_clear_path_betwee(board, f_from, r_from, rookFile, r_from) then~
_( boardState, false )~
else if Attackers(board, f_from, r_from, attackerColor ) or~
Attackers(board, f_from+sign(f_to-f_from), r_from, attackerColor ) then~
{ Can't castle out of or through check }~
_( boardState, false )~
else ( ~
{castle legal }~
Local bs := basic_move(boardState, fromSquare, toSquare, pc, removeCastleOptKside:true, removeCastleOptQside:true );~
bs := Set_square( bs, coord_to_square( f_from + sign(f_to-f_from), r_from), turn&"R" );~
bs := Set_square( bs, coord_to_square( rookFile, r_from ), null );~
_(bs, true )~
)~
~
) else if abs(f_from-f_to)>1 or abs(r_from-r_to)>1 then (~
_( boardState, false )~
) else (~
_( basic_move( boardState, fromSquare, toSquare, pc, removeCastleOptKside:true, removeCastleoptQside:true ), true )~
)
NodeLocation: 592,360,1
NodeSize: 64,24
WindState: 2,1694,-17,1436,1046
Function Is_clear_path_betwee( board : [File, Rank1] ;~
f_from, r_from : positive atom ;~
f_to, r_to : positive atom )
Title: Is clear path between
Description: Returns true if the squares between from and to are all clear, not counting the end points. from and to must be either on a diagonal or horizontal/vertical from each other (i.e., Queen move away from each other).
Definition: Local nSteps := max([abs(f_from-f_to),abs(r_from-r_to)]);~
Local fDir := sign(f_to-f_from), rDir:= sign(r_to-r_from);~
~
LocalIndex I := Sequence(1,nSteps-1,strict:true);~
Local inIntermedSq := board[@File=f_from+I*fDir,Rank1=r_from+I*rDir];~
~
Max( inIntermedSq<>null, I)<>true
NodeLocation: 128,184,1
NodeSize: 64,24
WindState: 2,98,82,803,495
Function King_attacker( board : [File, Rank1] ;~
fileNum, rank : positive atom ;~
attackerColor : text atom~
)
Title: King attacker
Description: Tests whether the king attacks the indicated square. If so, returns the a one-element set that contains the location of the attacking king. If not, returns null.
Definition: Localindex df:=-1..1;~
LocalIndex dr:=-1..1;~
Local sq := coord_to_square(fileNum+df, rank+dr);~
local pc := board[@File=fileNum+df, Rank1=rank+dr];~
Local (c,ty) := Piece_to_color_type(pc);~
Local attacked := c=attackerColor and not (df=0 and dr=0) and ty='K';~
ToSet( Unique(sq, condition:attacked) )
NodeLocation: 760,360,1
NodeSize: 64,24
WindState: 2,2023,14,720,560
Function Knight_attackers( board : [File, Rank1] ;~
fileNum, rank : positive atom ;~
attackerColor : text atom )
Title: Knight attackers
Description: Returns a board of booleans . True means a knight is attacking the given square.
Definition: Local pc := board[@File=filenum+Knight_d_file, Rank1=rank+Knight_d_rank];~
Local sq := coord_to_square(filenum+Knight_d_file, rank+Knight_d_rank);~
Local (c,ty) := Piece_to_color_type(pc);~
Local attacked := c=attackerColor and ty='N';~
ToSet( Unique(sq, condition:attacked) )
NodeLocation: 760,176,1
NodeSize: 64,24
WindState: 2,1775,203,1027,350
Function First_piece_in_direc( board : [ File, Rank1 ] ;~
f_coord, r_coord : positive atom ;~
f_dir, r_dir : number atom ~
)
Title: First piece in direction
Description: f_dir and r_dir should be -1, 0 or 1, with at least one non-zero. Returns the first piece encountered in the given direction.
Definition: LocalIndex I:=1..7;~
Local pc := board[@File=f_coord + f_dir*I, Rank1=r_coord + r_dir*I];~
Local pos := CondMin(I, pc<>null, I );~
if posnull
NodeLocation: 592,432,1
NodeSize: 64,24
WindState: 2,24,262,921,386
Function King_coord( board : [File, Rank1 ] ;~
color : text atom )
Title: King coord
Description: Returns the coordinate of color's king (as two return values, fileNum then rank.
Definition: Local loc := ArgMax(board=(color&'K'), File, Rank1);~
{!-60401|Try( IndexValue(loc.Dim), catch:null );} { work-around for bug Ew20904 }~
Local fileLetter := loc[.Dim=Handle(File)];~
Local fileNum := @[File=fileLetter];~
Local rank := loc[.Dim=Handle(Rank1)];~
_(fileNum,rank)
NodeLocation: 592,496,1
NodeSize: 64,24
WindState: 2,200,241,923,434
Function First_occupied_in_di( board : [ File, Rank1 ] ;~
f_coord, r_coord : positive atom ;~
f_dir, r_dir : number atom ~
)
Title: First occupied in direction
Description: f_dir and r_dir should be -1, 0 or 1, with at least one non-zero. Returns the square of the first piece encountered in the given direction.~
~
Returns the piece as the second return value.
Definition: LocalIndex I:=1..7;~
Local sq := coord_to_square(f_coord + f_dir*I, r_coord + r_dir*I);~
Local pc := Piece_at( board, sq);~
Local posOcc := SubIndex(pc<>null, True, I, first:true);~
_( sq[I=posOcc], pc[I=posOcc] )~
NodeLocation: 128,128,1
NodeSize: 64,24
WindState: 2,2154,108,748,525
Function FirstMatch( x : [I] ; condition : boolean [I] ; I : Index )
Title: FirstMatch
Description: Returns the first element of «x» along «I» for which «condition» is true.~
Returns null if «condition» is never true.
Definition: x[I=SubIndex( condition<>false, True, I, first:true )]
NodeLocation: 296,64,1
NodeSize: 64,24
WindState: 2,930,610,720,350
Function Pawn_move_candidates( ~
pawnSquare : text atom ;~
color : text atom~
)
Title: Pawn move candidates
Description: Returns the set of possible moves for the pawn at the indicated square, or null if it isn't a pawn on that square or there are no possible moves.
Definition: Local startRank := If color='W' then 2 else 7;~
Local dir := If color='W' then 1 else -1;~
Local (f,r) := square_to_coord(pawnSquare);~
~
Local takeLeft := coord_to_square( f-1, r+dir );~
Local takeRight := coord_to_square( f+1, r+dir );~
Local advance := coord_to_square(f,r+dir);~
Local advance2 := if r=startRank then coord_to_square(f,r+dir+dir);~
~
[takeLeft, takeRight, advance, advance2]
NodeLocation: 928,64,1
NodeSize: 64,24
WindState: 2,2084,291,833,599
Function King_move_candidates( ~
kingSquare : text atom ~
)
Title: King move candidates
Description: Returns the set of possible moves for the kind at the indicated square, or null if it isn't a pawn on that square or there are no possible moves.
Definition: Local (f,r) := square_to_coord(kingSquare);~
LocalIndex df:=-1..1;~
LocalIndex dr:=-1..1;~
Local castleMoves := ~
if kingSquare='e1' then ['g1','c1']~
else if kingSquare='e8' then ['g8','c8']~
else [];~
Concat( Flatten(coord_to_square( f+df, r+dr ), df,dr), castleMoves )
NodeLocation: 928,360,1
NodeSize: 64,24
WindState: 2,2325,55,852,570
Function Rook_move_candidates( ~
rookSquare : text atom ~
)
Title: Rook move candidates
Description: Returns the set of possible moves for the pawn at the indicated square, or null if it isn't a rook on that square or there are no possible moves.
Definition: Local (f,r) := square_to_coord(rookSquare);~
Concat( coord_to_square( @File, r ), coord_to_square( f, Rank1 ) )
NodeLocation: 928,120,1
NodeSize: 64,24
WindState: 2,2156,10,1061,557
Function Knight_move_candidat( ~
knightSquare : text atom ~
)
Title: Knight move candidates
Description: Returns the set of possible moves for the knight at the indicated square, or null if it isn't a knight on that square or there are no possible moves.
Definition: Local (f,r) := square_to_coord(knightSquare);~
coord_to_square( f+Knight_d_file, r+Knight_d_rank );~
NodeLocation: 928,176,1
NodeSize: 64,24
WindState: 2,2204,11,880,350
Function Bishop_move_candidat( ~
bishopSquare : text atom ~
)
Title: Bishop move candidates
Description: Returns the set of possible moves for the bishop at the indicated square, or null if it isn't a bishop on that square or there are no possible moves.
Definition: Local (f,r) := square_to_coord(bishopSquare);~
coord_to_square( @File, r + rank_dir*(@File-f))
NodeLocation: 928,232,1
NodeSize: 64,24
WindState: 2,2346,615,862,506
Function Queen_move_candidate( ~
queenSquare : text atom ~
)
Title: Queen move candidates
Description: Returns the set of possible moves for the queen at the indicated square, or null if it isn't a queen on that square or there are no possible moves.
Definition: Local (f,r) := square_to_coord(queenSquare);~
Local candidateDiag := coord_to_square( @File, r + rank_dir*(@File-f));~
Local candidateStraight := Concat( coord_to_square( @File, r ), coord_to_square( f, Rank1 ) );~
Concat( candidateDiag, candidateStraight, File )
NodeLocation: 928,296,1
NodeSize: 64,24
WindState: 2,1737,629,1149,350
Function ToSet( L : List )
Title: ToSet
Description: Adds a ref to L if there are any elements, or returns Null if empty
Definition: if size(L)=0 then null else \L
NodeLocation: 136,552,1
NodeSize: 64,24
WindState: 2,1170,653,720,350
Function Legal_moves_from_can( boardState : [Board_state_rec] ;~
squareToMove : text atom ;~
candidateSquares : text orNull reduced~
)
Title: Legal moves from candidates
Description: Returns a set of valid moves for the piece at squareToMove given a set of candidate moves, or Null if there are no valid moves in the set.
Definition: { ** TO DO ** -- include promotion option }~
LocalIndex to := Flatten(candidateSquares, ...indexesOf(candidateSquares), condition:candidateSquares<>null);~
Local (newState, valid) := Try_move( boardState, squareToMove, to );~
ToSet(unique(to,condition:valid))
NodeLocation: 448,304,1
NodeSize: 64,32
WindState: 2,1738,633,901,471
Close Chess_helper_functio
Close Chess_library
Variable Current_board_state
Title: Current board state
Definition: Table(Board_state_rec)(\Array(Rank1,File,[Array(File,['BR','BN','BB','BQ','BK','BB','BN','BR']),Array(File,['BP','BP','BP','BP','BP','BP','BP','BP']),Array(File,[Null,Null,Null,Null,Null,Null,Null,Null]),Array(File,[Null,Null,Null,Null,Null,Null,Null,Null]),Array(File,[Null,Null,Null,Null,Null,Null,Null,Null]),Array(File,[Null,Null,Null,Null,Null,Null,Null,Null]),Array(File,['WP','WP','WP','WP','WP','WP','WP','WP']),Array(File,['WR','WN','WB','WQ','WK','WB','WN','WR'])]),'W',1,1,1,1,Null,0,1)
NodeLocation: 240,200,1
NodeSize: 64,24
DefnState: 2,100,106,1611,318,0,DFNM
{!40300|Att_DerefReformVal: [File,Rank1]}
Variable Selected_square
Title: Selected square
Definition: Null
NodeLocation: 240,272,1
NodeSize: 64,24
Variable View_perspective
Title: View perspective
Definition: 'W'
NodeLocation: 240,344,1
NodeSize: 64,24
Constant Select_piece_color
Title: Select piece color
Definition: 0x80ffff00
NodeLocation: 256,640,1
NodeSize: 64,24
Text Te1938363475
Description: GPT-3.5-instruct plays Stockfish at 1800 ELO
NodeLocation: 396,52,-1
NodeSize: 180,20
Variable Board_by_square
Title: Board by square
Definition: Local txt := Reverse(if cur_board=null then null else f"{File}{Rank1}: {Piece_name[Piece=cur_board]}",Rank1);~
~
f"Board square by square:~
{JoinText(JoinText( txt, File, CR), Rank1 )}"
NodeLocation: 784,192,1
NodeSize: 64,24
ValueState: 2,800,41,1145,791,,MIDM
ReformVal: [File,Rank1]
Variable cur_board
Title: cur board
Definition: #Current_board_state[Board_state_rec='rBoard']
NodeLocation: 416,200,1
NodeSize: 64,24
Constant CR
Title: CR
Definition: '~
'
NodeLocation: 784,120,1
NodeSize: 64,24
Variable Defended_by_descript
Title: Defended by description
Definition: Local flat := Flatten( ~
Local defenders[] := attacked_by_cur;~
Local sq[] := square_names;~
Local c[] := Piece_to_color_type( cur_board );~
if defenders<>null then f"{sq} is defended by {JoinText(#defenders, ,', ')}" else null~
, File, Rank1);~
~
f"Defended by:~
{JoinText( flat, flat.K, CR)}"
NodeLocation: 784,264,1
NodeSize: 64,24
ValueState: 2,1340,218,860,702,,MIDM
ReformVal: [File,Rank1]
Variable cur_turn
Title: cur turn
Definition: Current_board_state[Board_state_rec='Turn']
NodeLocation: 416,272,1
NodeSize: 64,24
Variable Piece_count_descript
Title: Piece count description
Definition: Local nWhite := Piece_type_counts(cur_board, 'W');~
Local nBlack := Piece_type_counts(cur_board, 'B');~
~
f"white piece counts:~
{JoinText( f"{piece_type_name}: {nWhite}", Piece_type, CR)}~
~
black piece counts:~
{JoinText( f"{piece_type_name}: {nBlack}", Piece_type, CR)}"
NodeLocation: 784,328,1
NodeSize: 64,24
ValueState: 2,666,411,580,499,,MIDM
Variable Avail_moves_descript
Title: Avail moves description
Definition: Local moveTxt :=~
Local movesFrom[] := Avail_moves( Current_board_state ) Do~
if IsReference(movesFrom) Then (~
Local from[] := Square_names;~
Local piece[] := Get_piece_at(Current_board_state, square_names );~
Local (c,ty) := Piece_to_color_type(piece);~
f"{Piece_type_name[Piece_type=ty]} at {from}: {JoinText( #movesFrom, , ',')}"~
) else~
null;~
~
Local flatMoveTxt := Flatten(moveTxt, Rank1, File, condition:moveTxt<>null);~
~
f"Available moves:~
{JoinText(flatMoveTxt, flatMoveTxt.K, CR)}"
NodeLocation: 784,400,1
NodeSize: 64,24
ValueState: 2,1618,487,725,537,,MIDM
Variable FEN_of_current_posit
Title: FEN of current position
Definition: FEN_string(Current_board_state)
NodeLocation: 784,472,1
NodeSize: 64,24
ValueState: 2,468,474,1232,303,,MIDM
Aliases: FormNode Fo1164481619
Variable Current_state_prompt
Title: Current state prompt
Definition: f"Board FEN:~
{FEN_of_current_posit}~
~
{if cur_turn='B' then "Black" else "White"} to move.~
~
{Board_by_square}~
~
{Defended_by_descript}~
~
{ Attacked_by_descript}~
~
{Attacking_descriptio}~
~
{You_hanging_pieces}~
~
{Oppenent_hanging_des}~
~
{Piece_count_descript}~
~
{Avail_moves_descript}"
NodeLocation: 784,544,1
NodeSize: 64,24
ValueState: 2,1351,8,1171,865,,MIDM
Constant GPT_instructions
Title: GPT instructions
Definition: 'Write an internal monologue of the thought process of deciding the best move to make.~
Follow this process:~
1. Identify the opening, relevant theory for opening goals, middlegame goals, etc.~
2. For the current board situation, write out some heuristics to use to think about the board.~
3. Identify some promising candidate moves.~
4. For each candidate move, consider counter-moves, counter-counter-moves, etc. Use the "Attacked or defended by" section to help.~
5. After considering a move, enumerate any pieces that could attack the destination square.~
6. Decide on the best move to make.~
7. Write the best move on a separate line in the format~
Move=square->square~
such as ~
Move=b1->c3~
Do not vary from this notation for the move, and don''t add any addition words or characters to that line. Make that the last line of your response.'
NodeLocation: 784,616,1
NodeSize: 64,24
Decision GPT_model
Title: GPT model
Definition: Choice(Self,2)
NodeLocation: 1144,448,1
NodeSize: 64,24
Aliases: FormNode Fo168834131
{!40300|DomainExpr: Discrete('gpt-3.5-turbo','gpt-3.5-turbo-instruct','gpt-4')}
Variable Full_prompt
Title: Full prompt
Definition: f"{GPT_instructions}~
~
{Current_state_prompt}~
~
internal_monologue="
NodeLocation: 984,544,1
NodeSize: 64,24
ValueState: 2,244,250,1075,517,,MIDM
Include 0,LinkLibrary OpenAI_API_lib,2,2,0,0,..\Src\AI Assistant Prototype\OpenAI API lib.ana
NodeLocation OpenAI_API_lib: 112,120,1
NodeSize OpenAI_API_lib: 64,24
Variable GPT_response
Title: GPT response
Definition: Prompt_completion( Full_prompt, modelName:GPT_model, timeout:120k {ms}, ~
max_tokens:if GPT_model='gpt-3.5-turbo-instruct' then 2000 else Undefined~
)
NodeLocation: 1144,544,1
NodeSize: 64,24
ValueState: 2,1503,64,1565,853,,MIDM
Variable available_moves
Title: available moves
Definition: Avail_moves( Current_board_state )
NodeLocation: 416,416,1
NodeSize: 64,24
ValueState: 2,87,309,831,303,,MIDM
ReformVal: [File,Rank1]
Variable GPT_move
Title: GPT move
Definition: FindInText("Move\s*=([\s\w]*)(?[a-h][1-8])\s*->\s*(?[a-h][1-8])", GPT_response, subpattern:From_to, caseInsensitive:true, return:'S' )
NodeLocation: 1144,608,1
NodeSize: 64,24
ValueState: 2,1842,734,416,303,,MIDM
Variable Board_state_after_GP
Title: Board state after GPT move
Definition: (, Is_GPT_move_legal_) := Try_move( Current_board_state, GPT_move[from_to='from'], GPT_move[from_to='to'] )
NodeLocation: 1312,608,1
NodeSize: 64,32
Variable Is_GPT_move_legal_
Title: Is GPT move legal?
Definition: ComputedBy(Board_state_after_GP)
NodeLocation: 1312,696,1
NodeSize: 64,24
Variable GPT_s_previous_respo
Title: GPT's previous response
Definition: 'I need to make the best move to continue my game and ultimately win. I should start by identifying the opening and relevant theory to meet my opening goals. Currently, I have equal pieces with my opponent, so I need to focus on creating strong middlegame positions. I can use several heuristics such as controlling the center, developing my pieces, and attacking the opponent''s weaknesses. Looking at the board, I see several promising candidate moves, including moving my knight from g8 to f6 or h6, or moving my pawn from d7 to d6 or d5. But I need to consider counter-moves and counter-counter-moves for each option, taking into account which pieces are being attacked or defended. For example, if I were to move my knight to h6, it could eventually be attacked by my opponent''s pawn on g5. I also need to keep in mind any pieces that could attack the destination square, such as my opponent''s knight on c6 attacking the square I want to move my knight to on h6. After carefully considering all of these factors, I believe the best move to make is to move my knight from g8 to f6. This allows me to develop my piece, control the center, and potentially attack my opponent''s king in the long run. ~
~
Move=g8->f6'
NodeLocation: 1144,344,1
NodeSize: 64,24
ValueState: 2,1564,26,1176,1060,,MIDM
Variable Who_s_turn_
Title: Who's turn:
Definition: f"{if cur_turn='B' then 'Black' else 'White'} to move."
NodeLocation: 416,344,1
NodeSize: 64,24
Aliases: FormNode Fo243045459
Decision GPT_auto_move
Title: GPT auto move
Definition: Choice(Self,2,0)
NodeLocation: 944,48,1
NodeSize: 64,24
Aliases: FormNode Fo751473747
{!40300|DomainExpr: Discrete('No','GPT plays black','GPT plays white',type:'text')}
Variable Prev_move_from
Title: Prev move from
Definition: Null
NodeLocation: 240,416,1
NodeSize: 64,24
Variable Prev_move_to
Title: Prev move to
Definition: Null
NodeLocation: 240,472,1
NodeSize: 64,24
Constant Prev_move_highlight_
Title: Prev move highlight color
Definition: 0x8000ffff;0x80ffff00
NodeLocation: 256,696,1
NodeSize: 64,24
Variable Highlight_colors
Title: Highlight colors
Definition: if Selected_square=null then ~
Max( [ ~
Square_to_grid(Selected_square, Select_piece_color ),~
Square_to_grid(Prev_move_from, Prev_move_highlight_ ),~
Square_to_grid(Prev_move_to, Prev_move_highlight_ )~
])~
else~
Square_to_grid(Selected_square, Select_piece_color )
NodeLocation: 408,640,1
NodeSize: 64,24
ValueState: 2,260,266,712,281,,MIDM
ReformVal: [File,Rank1]
NumberFormat: 2,H,8,2,0,0,8,0,$,0,"ABBREV",0,,,0,0,15,,0
{!40700|Att_CellFormat: Undefined}
Variable Attacked_by_descript
Title: Attacked by description
Definition: Local gridTxt := (~
Local mySq[] := if cur_turn = Piece_to_color_type( cur_board ) then square_names else null;~
if mySq<>null then (~
Local (f,r) := square_to_coord(mySq);~
Local attackers := Attackers(cur_board, f,r, if cur_turn='B' then 'W' else 'B');~
if attackers=null then null else (~
f"{mySq} is attacked by {JoinText( #attackers, ,', ')}"~
)~
) else null~
);~
Local flat := Flatten(gridTxt, File, Rank1);~
f"You pieces attacked by opponent:~
{JoinText(flat, flat.K, CR)}"
NodeLocation: 952,264,1
NodeSize: 64,24
WindState: 2,1197,205,1147,535
ValueState: 2,708,714,785,303,,MIDM
ReformVal: [File,Rank1]
Variable Attacking_descriptio
Title: Attacking description
Definition: Local gridTxt := (~
Local oppSq[] := if (If cur_turn='W' then 'B' else 'W') = Piece_to_color_type( cur_board ) then square_names else null;~
if oppSq<>null then (~
Local (f,r) := square_to_coord(oppSq);~
Local attackers := Attackers(cur_board, f,r, cur_turn);~
if attackers=null then null else (~
f"{oppSq} is attacked by {JoinText( #attackers, ,', ')}"~
)~
) else null;~
);~
Local flat := Flatten(gridTxt, File, Rank1);~
f"Opponent's pieces attacked by you:~
{JoinText(flat, flat.K, CR)}"
NodeLocation: 952,328,1
NodeSize: 64,24
ValueState: 2,708,714,785,303,,MIDM
ReformVal: [File,Rank1]
Variable You_hanging_pieces
Title: You hanging pieces
Definition: Local opp_color := if cur_turn='W' then 'B' else 'W';~
Local c := Piece_to_color_type(cur_board);~
Local hanging := Unique(square_names, condition: c=opp_color and attacked_by_cur=null);~
f"These pieces of yours are hanging: {if size(hanging)=0 then 'None' Else JoinText(hanging,,', ')}"~
NodeLocation: 952,192,1
NodeSize: 64,24
ValueState: 2,324,330,740,266,,MIDM
Variable attacked_by_cur
Title: attacked by cur
Definition: Attackers(cur_board, @File, Rank1, cur_turn)
NodeLocation: 608,240,1
NodeSize: 64,24
Variable attacked_by_oppenent
Title: attacked by oppenent
Definition: Attackers(cur_board, @File, Rank1, if cur_turn='W' then 'B' else 'W')
NodeLocation: 608,304,1
NodeSize: 64,24
Variable Oppenent_hanging_des
Title: Oppenent hanging desc
Definition: Local c := Piece_to_color_type(cur_board);~
Local hanging := Unique(square_names, condition: c=cur_turn and attacked_by_cur=null);~
f"These opponent pieces are hanging: {if size(hanging)=0 then 'None' Else JoinText(hanging,,', ')}"~
NodeLocation: 1104,192,1
NodeSize: 64,24
Variable invalidate_next_time
Title: invalidate GPT response next time
Definition: 0
NodeLocation: 576,640,1
NodeSize: 64,32
Variable game_over
Title: game over
Definition: Max(available_moves<>null,File,Rank1)=0
NodeLocation: 416,480,1
NodeSize: 64,24
Button Maybe_automove
Title: Maybe automove
NodeLocation: 784,708,1
NodeSize: 64,28
WindState: 2,588,525,720,350
OnClick: if ((GPT_auto_move='GPT plays black' and cur_turn='B') or ~
(GPT_auto_move='GPT plays white' and cur_turn='W')) ~
and not game_over then ~
Let_GPT_move;~
Variable description_of_illeg
Title: description of illegal GPT move
Definition: if Max(GPT_move=null,from_to) then (~
Local lastLine := FindInText("[^\r\n]+$", GPT_response, re:true, return:'S');~
f"GPT did not provide a move in the correct format. It wrote: ~
{lastLine}~
To try again, press the [Let GPT move] button"~
) else (~
f"GPT's move, {GPT_move[from_to='from']}->{GPT_move[from_to='to']}, is not legal. To try again, press the [Let GPT move] button"~
)
NodeLocation: 1152,752,1
NodeSize: 64,32
ValueState: 2,2590,676,416,303,,MIDM
Button Reset_to_start_witho
Title: Reset to start without automove
NodeLocation: 1312,204,1
NodeSize: 64,36
{!40300|ProactivelyEvaluate: 32}
OnClick: Current_board_state := Starting_board;~
Selected_square := null;~
Prev_move_from := null;~
Prev_move_to := null;~
Refresh_board_image;
Close Implementation
Text Te1261540435
Title: Instructions:
Description: ~
To play, you MUST be in browse mode.~
~
To make a move, click on the piece so that it highlights, then click on the square to move to.~
~
Limitations. These rules of chess are not detected or enforced:~
1. draw by repetition~
2. draw by 50-move rule
NodeLocation: 1040,352,-1
NodeSize: 408,272
FormNode Fo168834131
Title: GPT model
Definition: 0
NodeLocation: 792,48,1
NodeSize: 152,16
NodeInfo: 1,,,,,,,198,,,,,,0
Original: GPT_model
Close Chess_with_GPT
{!-40499|MsgBox("This Analytica model file contains text characters encoded in UTF-8 (Unicode) format, not ASCII. It was saved from Analytica release 6.4. You need to upgrade to Analytica 6.4 to read the model correctly. If you use it with this release, the Unicode characters may look strange and parts of the model may not work.",16,"Analytica 6.4 required")}