2048.ai
Join the numbers and get to the 2048 tile!
0
ms per move
Delay:
100
ms
Downloading Weights (--/-- MB)
2010-കളിൽ നിങ്ങൾ ഇന്റർനെറ്റിൽ ഉണ്ടായിരുന്നെങ്കിൽ, ബുദ്ധിമുട്ടുള്ള ഗെയിമായ 2048 നിങ്ങൾക്ക് പരിചിതമായിരിക്കാം. മെഷീൻ ലേണിംഗിന്റെ ശക്തി ഉപയോഗിച്ച് നമുക്ക് എത്ര ഉയർന്ന സ്കോർ നേടാനാകും എന്ന് നോക്കാം.
ഗെയിം മെക്കാനിക്സ്
ഗെയിം ഇനിപ്പറയുന്ന രീതിയിൽ പ്രവർത്തിക്കുന്നു. ബോർഡ് 2 റാൻഡം ടൈലുകളുമായി ആരംഭിക്കുന്നു.
ഓരോ റാൻഡം ടൈലിനും 2 ആകാനുള്ള സാധ്യത 90% ഉം 4 ആകാനുള്ള സാധ്യത
10% ഉം ആണ്.
4 സാധ്യമായ നീക്കങ്ങൾ ഉണ്ട്: മുകളിലേക്ക്, താഴേക്ക്, ഇടത്തേക്ക്, വലത്തേക്ക്. ഓരോ നീക്കവും ബോർഡിലെ ഒരു “സ്ലൈഡിംഗ്” ചലനവുമായി യോജിക്കുന്നു, അവിടെ എല്ലാ ടൈലുകളും മറ്റൊരു ടൈലുമായി കൂട്ടിയിടിക്കുന്നത് വരെ ആ ദിശയിലേക്ക് നീക്കപ്പെടുന്നു. രണ്ട് ടൈലുകൾക്ക് ഒരേ മൂല്യം ഉണ്ടെങ്കിൽ, ആ ടൈലുകൾ മൂല്യമുള്ള ഒരു ഉയർന്ന ടൈലായി ലയിക്കുന്നു. ഓരോ തവണ ലയിപ്പിക്കുമ്പോഴും, നമ്മുടെ സ്കോർ കൊണ്ട് വർദ്ധിക്കുന്നു.
അത് അത്രയും കഠിനമാണോ?
അതെ, അതാണ്. ഏതെങ്കിലും ഉയർന്ന ടൈൽ നേടാൻ കുറഞ്ഞത്. എന്തുകൊണ്ടെന്ന് കാണാൻ, നിങ്ങൾ 1024 നേടിയതായി കരുതുക. അപ്പോൾ, ആ സ്കോർ നേടാൻ നിങ്ങൾ 16 സ്ക്വയറുകൾ ഒരു “സ്ക്രാച്ച്പാഡ്” ആയി ഉപയോഗിച്ചിട്ടുണ്ട്. എന്നാൽ 2048 നേടാൻ, നിങ്ങൾക്ക് സ്ക്വയറുകൾ ഒരു സ്ക്രാച്ച്പാഡ് ആയി ഉപയോഗിച്ച് മറ്റൊരു 1024 നിർമ്മിക്കേണ്ടതുണ്ട്. 4096 നേടാൻ, 14 ടൈലുകൾ ഉപയോഗിച്ച് അത് ചെയ്യേണ്ടതുണ്ട്, ഇതുപോലെ തുടരും. അതിനാൽ, സ്ഥലത്തിന്റെ പരിമിതികൾ മാത്രം കണക്കിലെടുത്ത് കണക്കാക്കാവുന്ന 3,932,156 എന്ന ഒരു സൈദ്ധാന്തിക പരമാവധി സ്കോർ യഥാർത്ഥത്തിൽ ഉണ്ട്. ഇന്ന് നമ്മൾ അവിടെ എത്താൻ പോകുന്നില്ല, പക്ഷേ മികച്ച മനുഷ്യരെ തോൽപ്പിക്കാൻ ശ്രമിക്കും.
രീതികൾ
നമ്മൾ ഉപയോഗിക്കാൻ പോകുന്ന രീതികൾ രണ്ട് വിഭാഗങ്ങളായി തിരിക്കാം: തിരയൽ-ആധാരിതവും പഠന-ആധാരിതവും. തിരയൽ-ആധാരിത രീതികൾ സാധ്യമായ നിരവധി ഗെയിം അവസ്ഥകൾ പര്യവേക്ഷണം ചെയ്യുകയും, ഏത് നീക്കമാണ് ഒരു ആവശ്യമുള്ള ഫലത്തിലേക്ക് ഏറ്റവും സാധ്യതയുള്ളത് എന്ന് അനുമാനിച്ചുകൊണ്ട് ഒരു ഊഹം രൂപപ്പെടുത്തുകയും ചെയ്യുന്നു. പഠന-ആധാരിത രീതികൾ ഒരു കളിക്കാരൻ മോഡൽ നിർവചിച്ച് ധാരാളം ഗെയിമുകൾ സിമുലേറ്റ് ചെയ്ത് അതിന്റെ പാരാമീറ്ററുകൾ പഠിക്കുന്നു.
റാൻഡം പ്ലേയർ
ഇതാണ് നമ്മുടെ അടിസ്ഥാന രേഖ. ഇത് വളരെ മോശമാണ്.
മോണ്ടെ കാർലോ
ഈ രീതി ഇങ്ങനെ പ്രവർത്തിക്കുന്നു:
- നമുക്ക് ഒരു പ്രധാന ബോർഡ് ഉണ്ട്, അതിൽ നമ്മൾ ഒപ്റ്റിമൽ നീക്കങ്ങൾ മാത്രമേ കളിക്കൂ
- ഓരോ സാധ്യമായ നീക്കത്തിനും , ബോർഡിന്റെ ഒരു പകർപ്പ് ഉണ്ടാക്കി, അതിൽ നീക്കം നടത്തുക
- പിന്നെ, ഒരു റാൻഡം കളിക്കാരൻ ആ ബോർഡിൽ നീക്കങ്ങൾ നടത്തട്ടെ അത് തോൽക്കുന്നത് വരെ. പിന്നെ, അവസാന ബോർഡിലെ ടൈലുകളുടെ ആകെത്തുക ഞങ്ങൾ സംരക്ഷിക്കുന്നു. ഇതാണ് നമ്മുടെ സ്കോർ.
- അത് തവണ ആവർത്തിക്കുക, ഇവിടെ ഉയർന്ന എന്നാൽ കൂടുതൽ കളികൾ പര്യവേക്ഷണം ചെയ്തത് എന്നാണ്.
- ഉയർന്ന ശരാശരി സ്കോർ ഉള്ള നീക്കം ഒപ്റ്റിമൽ നീക്കമായി തിരഞ്ഞെടുക്കുക.
ഇതാ സ്യൂഡോകോഡ്:
def choose_best_move(board):
scores = [] # ടൈലുകളുടെ ശരാശരി ആകെത്തുകയുടെ ലിസ്റ്റ്
moves = [UP, DOWN, LEFT, RIGHT]
for move in moves:
# ബോർഡിന്റെ ഒരു പകർപ്പ് ഉണ്ടാക്കുക
board_copy = copy(board)
# നീക്കം നടത്തുക (ടൈൽ സ്പോൺ ഉൾപ്പെടുന്നു)
board_copy.make_move(move)
tile_sums = []
# ഈ നീക്കം നൽകിയിട്ടുള്ളതിനാൽ, ഞങ്ങൾ ഒരു റാൻഡം കളിക്കാരനെ അനുവദിക്കുന്നു
# കളി അവസാനിക്കുന്നത് വരെ കളിക്കാൻ. പിന്നെ, ഞങ്ങൾ റെക്കോർഡ് ചെയ്യുന്നു
# ബോർഡിലെ അവസാന ടൈലുകളുടെ ശരാശരി ആകെത്തുക.
for n in range(num_games):
board_copy2 = copy(board_copy)
# ഒരു റാൻഡം ഏജന്റിനെ തോൽക്കുന്നത് വരെ കളിക്കാൻ അനുവദിക്കുക
board_copy2.random_game()
sums.append(board_copy2.tile_sum())
# തോൽക്കുന്ന കോൺഫിഗറേഷനിലെ ടൈലുകളുടെ ശരാശരി ആകെത്തുക സംരക്ഷിക്കുക
scores.append(sum(tile_sums) / len(tile_sums))
return moves[argmax(scores)]
എൻ-ട്യൂപ്പിൾ നെറ്റ്വർക്ക്
റാംനെറ്റുകൾ എന്ന ആശയമായി ആദ്യം ഉരുത്തിരിഞ്ഞ എൻ-ട്യൂപ്പിൾ നെറ്റ്വർക്കുകൾ, ടെമ്പറൽ ഡിഫറൻസ് ലേണിംഗ് ഉപയോഗിച്ച് പരിശീലിപ്പിക്കുമ്പോൾ 2048 കളിക്കുന്നതിൽ അതീവ ഫലപ്രദമാണെന്ന് കണ്ടെത്തിയിട്ടുണ്ട്. ഇവ ഒരു ഫംഗ്ഷൻ നിർവചിക്കുന്നു, അത് ബൈനറിയിൽ എൻകോഡ് ചെയ്ത ചില ഫീച്ചറുകളെ ഒരു സ്കോറിലേക്ക് മാപ്പ് ചെയ്യുന്നു. ആ സ്കോർ ആ പ്രത്യേക ഫീച്ചർ എത്ര നല്ലതാണ് എന്നതിന്റെ പ്രതിനിധാനമാണ്.
ഈ ഫംഗ്ഷൻ, മിക്ക ആധുനിക നാഡീജാലങ്ങളിൽ നിന്ന് വ്യത്യസ്തമായി, കണക്കാക്കുന്നതല്ല മറിച്ച് ഒരു അറേയിൽ സംഭരിച്ചിരിക്കുന്നു. ഈ അറേയിലെ ഓരോ ഘടകവും അതിന്റെ സൂചികയുമായി ബന്ധപ്പെട്ട ഫീച്ചറിന്റെ സ്കോർ പ്രതിനിധീകരിക്കുന്നു.
ഈ അറേയിലേക്ക് എങ്ങനെ സൂചികയിടാം എന്ന് മനസ്സിലാക്കാൻ, ഗെയിം ബോർഡിന്റെ നടത്തിപ്പ് നോക്കാം.
ബോർഡ് നടപ്പിലാക്കൽ
struct Board {
raw: u64,
}
ശരിയാണ്, ഞങ്ങൾ മുഴുവൻ കാര്യവും ഒരു 64 ബിറ്റ് അൺസൈൻഡ് ഇന്റീജറിൽ ഉൾക്കൊള്ളിക്കുന്നു. ഇത് ഞങ്ങൾ ഇങ്ങനെ ചെയ്യുന്നു:
- ഓരോ ടൈൽ മൂല്യവും ഒന്നുകിൽ ശൂന്യമാണ്, അല്ലെങ്കിൽ ആണ്, ഇവിടെ
- പരിചയത്തിൽ നിന്ന്, ടൈൽ നമുക്ക് ലഭിക്കാൻ സാധ്യതയില്ല.
ഇത് എന്ന പരിധിയിലെത്തിക്കുന്നു. അതിനാൽ, ഓരോ ടൈലിനും സാധ്യമായ മൂല്യങ്ങൾ ഉണ്ട്, അതായത് നമുക്ക് അത് ബിറ്റുകളിൽ പാക്ക് ചെയ്യാം. ടൈൽ മൂല്യം തിരികെ ലഭിക്കാൻ നമ്മൾ ഇത് ഉപയോഗിക്കുന്നു:
നിർമ്മാണശൈലി
ഞങ്ങൾ ഉപയോഗിക്കുന്ന നെറ്റ്വർക്ക് ഒരു ട്യൂപ്പിൾ നെറ്റ്വർക്കാണ്, അതിന് 4 ഫീച്ചറുകളുണ്ട്. ഓരോ ഫീച്ചറും ബോർഡിലെ ടൈലുകളുടെ ഒരു കോൺഫിഗറേഷൻ പ്രതിനിധീകരിക്കുന്നു. ഓരോ ടൈലും ബിറ്റുകൾ ഉപയോഗിക്കുന്നതിനാൽ, ഓരോ ഫീച്ചറും ബിറ്റുകൾ ഉപയോഗിക്കും.
ഞങ്ങളുടെ നെറ്റ്വർക്ക് ഒരു ഫീച്ചർ സ്കോർ മാപ്പ് ആയതിനാൽ, ഓരോ ഫീച്ചറും സംഭരിക്കാൻ 32-ബിറ്റ് ഫ്ലോട്ടുകളുടെ ഒരു അറേ ഞങ്ങൾ ഉപയോഗിക്കുന്നു. ഓരോ ഫ്ലോട്ടും 4 ബൈറ്റ് ആയതിനാൽ, ഇത് ഞങ്ങളുടെ നെറ്റ്വർക്ക് വലുപ്പം ബൈറ്റുകളായി ഉയർത്തുന്നു.
നമുക്ക് ചെയ്യാൻ കഴിയുന്ന ഒരു സൗകര്യപ്രദമായ നിരീക്ഷണം എന്തെന്നാൽ, ഫീച്ചറിന്റെ മൂല്യം ബോർഡിലെ അതിന്റെ സ്ഥാനത്തെ ആശ്രയിച്ച് മാറരുത് എന്നതാണ്. ഉദാഹരണത്തിന്, ടൈലുകളുള്ള ഒരു വരി ബോർഡിന്റെ മുകളിലാണോ, താഴെയാണോ, ഇടതുവശത്താണോ, വലതുവശത്താണോ എന്നത് പ്രശ്നമല്ല, അത് തുല്യമായി നല്ലതാണ്. വാസ്തവത്തിൽ, അതിന്റെ ക്രമം ഞങ്ങൾ വിപരീതമാക്കിയാലും, അത് അത്രതന്നെ നല്ലതാണ്. ഇതിനർത്ഥം ബോർഡിന്റെ എല്ലാ ഓറിയന്റേഷനുകളിലോ, അല്ലെങ്കിൽ സമമിതികളിലോ ഫീച്ചറിന്റെ സ്കോർ കണക്കാക്കാൻ നമുക്ക് ഒരേ ഭാരങ്ങൾ പുനരുപയോഗിക്കാം എന്നാണ്. ഒരു ചതുരത്തിന് 8 അത്തരം സമമിതികൾ ഉണ്ട്, അത് ഞങ്ങൾ താഴെ കാണിക്കുന്നു.