{ 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")}