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)]
N-ട്യൂപ്പിൾ നെറ്റ്വർക്ക്
N-ട്യൂപ്പിൾ നെറ്റ്വർക്കുകൾ, ആദ്യം RAMnets ആയി ആലോചിച്ചത്, 2048 കളിക്കുന്നതിൽ വളരെ മികച്ചതായി കണ്ടെത്തിയിട്ടുണ്ട്, പ്രത്യേകിച്ച് ടെമ്പറൽ ഡിഫറൻസ് ലേണിംഗ് ഉപയോഗിച്ച് പരിശീലിപ്പിക്കുമ്പോൾ. ഇവ ഒരു ഫംഗ്ഷൻ നിർവചിക്കുന്നു, ഇത് ബൈനറിയിൽ എൻകോഡ് ചെയ്ത ചില ഫീച്ചറുകളെ ഒരു സ്കോറിലേക്ക് മാപ്പ് ചെയ്യുന്നു, അത് ആ ഫീച്ചർ എത്ര നല്ലതാണ് എന്നതിനെ പ്രതിനിധീകരിക്കുന്നു.
ഈ ഫംഗ്ഷൻ, മിക്ക ആധുനിക നിയൂറൽ നെറ്റ്വർക്കുകളിൽ നിന്ന് വ്യത്യസ്തമായി, കണക്കാക്കപ്പെടുന്നില്ല, പകരം ഒരു അറേയിൽ സംഭരിച്ചിരിക്കുന്നു, അതിലെ ഓരോ ഘടകവും അതിന്റെ സൂചികയുമായി ബന്ധപ്പെട്ട ഫീച്ചറിന്റെ സ്കോർ പ്രതിനിധീകരിക്കുന്നു.
ഈ അറേയിലേക്ക് എങ്ങനെ സൂചികയിലേക്ക് പ്രവേശിക്കാമെന്ന് മനസ്സിലാക്കാൻ, ഗെയിം ബോർഡിന്റെ ഇംപ്ലിമെന്റേഷൻ നോക്കാം.
ബോർഡ് ഇംപ്ലിമെന്റേഷൻ
struct Board {
raw: u64,
}
ശരിയാണ്, ഞങ്ങൾ മുഴുവൻ കാര്യവും ഒരു 64 ബിറ്റ് അൺസൈൻഡ് ഇന്റിജറിലേക്ക് ഫിറ്റ് ചെയ്യുന്നു. ഇത് ചെയ്യുന്നതിന് ഞങ്ങൾ ഇനിപ്പറയുന്ന കാര്യങ്ങൾ നിരീക്ഷിക്കുന്നു:
- ഓരോ ടൈൽ മൂല്യവും ഒന്നുകിൽ ശൂന്യമാണ്, അല്ലെങ്കിൽ ആണ്, ഇവിടെ
- അനുഭവത്തിൽ നിന്ന്, ടൈൽ ഞങ്ങൾക്ക് ലഭിക്കാൻ സാധ്യതയില്ല.
ഇത് എന്ന പരിധിയിലേക്ക് നയിക്കുന്നു. അതിനാൽ, ഓരോ ടൈലിനും സാധ്യമായ മൂല്യങ്ങൾ ഉണ്ട്, അതായത് നമുക്ക് അത് ബിറ്റുകളിൽ പാക്ക് ചെയ്യാം. ടൈൽ മൂല്യം തിരികെ ലഭിക്കാൻ ഞങ്ങൾ ഇനിപ്പറയുന്നത് ഉപയോഗിക്കുന്നു:
ആർക്കിടെക്ചർ
ഞങ്ങൾ ഉപയോഗിക്കുന്ന നെറ്റ്വർക്ക് ഒരു ട്യൂപ്പിൾ നെറ്റ്വർക്ക് ആണ്, അതിന് 4 ഫീച്ചറുകൾ ഉണ്ട്, ഓരോ ഫീച്ചറും ബോർഡിലെ ടൈലുകളുടെ ഒരു കോൺഫിഗറേഷൻ പ്രതിനിധീകരിക്കുന്നു. ഓരോ ടൈലും ബിറ്റുകൾ ഉപയോഗിക്കുന്നതിനാൽ, ഓരോ ഫീച്ചറും ബിറ്റുകൾ ഉപയോഗിക്കും.
ഞങ്ങളുടെ നെറ്റ്വർക്ക് ഒരു ഫീച്ചർ സ്കോർ മാപ്പ് ആയതിനാൽ, ഓരോ ഫീച്ചറും സംഭരിക്കാൻ 32-ബിറ്റ് ഫ്ലോട്ടുകളുടെ ഒരു അറേ ഞങ്ങൾ ഉപയോഗിക്കുന്നു. ഓരോ ഫ്ലോട്ടും 4 ബൈറ്റുകൾ ആയതിനാൽ, ഇത് ഞങ്ങളുടെ നെറ്റ്വർക്ക് വലുപ്പം ബൈറ്റുകളായി ഉയർത്തുന്നു.
ഒരു സൗകര്യപ്രദമായ നിരീക്ഷണം നമുക്ക് നടത്താൻ കഴിയുന്നത്, ഫീച്ചറിന്റെ മൂല്യം ബോർഡിലെ അതിന്റെ സ്ഥാനത്തെ ആശ്രയിച്ച് മാറില്ല എന്നതാണ്. ഉദാഹരണത്തിന്, ടൈലുകളുള്ള ഒരു വരി ബോർഡിന്റെ മുകളിലോ, താഴെയോ, ഇടതോ, വലതോ ആയിരിക്കട്ടെ, അത് ഒരുപോലെ നല്ലതാണ്. വാസ്തവത്തിൽ, അതിന്റെ ക്രമം ഞങ്ങൾ തിരിച്ചാലും, അത് അത്രതന്നെ നല്ലതാണ്. ഇതിനർത്ഥം, ബോർഡിന്റെ എല്ലാ ഓറിയന്റേഷനുകളിലോ, സമമിതികളിലോ, ഫീച്ചറിന്റെ സ്കോർ കണക്കാക്കാൻ ഞങ്ങൾക്ക് ഒരേ ഭാരങ്ങൾ പുനരുപയോഗിക്കാം എന്നാണ്. ഒരു സ്ക്വയറിന് 8 അത്തരം സമമിതികൾ ഉണ്ട്, അത് ഞങ്ങൾ താഴെ കാണിക്കുന്നു.