Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Roux Antoine
AI_2048
Commits
0486ffd9
Commit
0486ffd9
authored
Nov 29, 2017
by
Antoine Roux
Browse files
started the genetic part, wrote functions, they need to be tested
parent
bffa7790
Changes
8
Hide whitespace changes
Inline
Side-by-side
2048.py
View file @
0486ffd9
...
...
@@ -4,24 +4,46 @@ import random
import
time
import
matplotlib.pyplot
as
plt
# class bcolors:
# HEADER = '\033[95m'
# OKBLUE = '\033[94m'
# OKGREEN = '\033[92m'
# WARNING = '\033[93m'
# FAIL = '\033[91m'
# ENDC = '\033[0m'
# BOLD = '\033[1m'
# UNDERLINE = '\033[4m'
# print (bcolors.OKBLUE + "Some text"
# + bcolors.ENDC)
##CMA-ES
# class Neuron (object) :
#
# def __init__ (self) :
# """
# """
# self.grid = Grid()
#
# for k in range (4) :
# for i in range (4) :
# self.grid.grid[k,i] = random.randint(-10, 10)
#
# self.fitnessValue = -1 #while unknown, it is set to -1
#
#
# def evaluate (self) :
# """ Attributes the rawScore as fitness
# Doesnt return anything
# """
# self.fitness = sum(sum(self.grid.grid))
###################################### Classes #########################################
class
Grid
(
object
)
:
def
__init__
(
self
,
grid
)
:
def
__init__
(
self
,
g
ivenGrid
,
givenFitnessG
rid
)
:
"""
"""
self
.
grid
=
np
.
array
(
grid
)
# self.grid = np.array([[0, 0, 0, 0],
# [0, 0, 0, 0],
# [0, 0, 0, 0],
# [0, 0, 0, 0]])
self
.
grid
=
np
.
array
(
givenGrid
)
# self.fitnessGrid = np.array([[8, 4, 2, 1],
# [16, 8, 4, 2],
# [32, 16, 8, 4],
# [64, 32, 16, 8]])
self
.
fitnessGrid
=
givenFitnessGrid
def
__str__
(
self
)
:
string
=
""
...
...
@@ -147,6 +169,7 @@ class Grid (object) :
randomPosition
=
random
.
randint
(
0
,
emptyCounter
-
1
)
counter
=
0
for
k
in
range
(
4
)
:
for
i
in
range
(
4
)
:
if
self
.
grid
[
k
,
i
]
==
0
:
...
...
@@ -157,62 +180,171 @@ class Grid (object) :
def
calcFitness
(
self
)
:
""" Returns the fitness of the grid
"""
# fitness
Array
= [[64, 16, 4, 1], #a peu près pareil
# fitness
Grid
= [[64, 16, 4, 1], #a peu près pareil
# [256, 64, 16, 4],
# [1024, 256, 64, 16],
# [4096, 1024, 256, 64]]
fitnessArray
=
[[
8
,
4
,
2
,
1
],
[
16
,
8
,
4
,
2
],
[
32
,
16
,
8
,
4
],
[
64
,
32
,
16
,
8
]]
fitness
=
0
for
k
in
range
(
4
)
:
for
i
in
range
(
4
)
:
fitness
+=
self
.
grid
[
k
,
i
]
*
fitnessArray
[
k
][
i
]
## pas nécessairement plus lent...
# fitness = 0
# for k in range(4) :
# for i in range (4) :
# fitness += self.grid[k,i] * self.fitnessGrid[k][i]
fitness
=
sum
(
sum
(
np
.
multiply
(
self
.
grid
,
self
.
fitnessGrid
)))
return
(
fitness
)
##############################################
class
Generation
(
object
)
:
def
__init__
(
self
,
givenSizeOfPopulation
)
:
"""
"""
self
.
sizeOfPopulation
=
givenSizeOfPopulation
self
.
individuals
=
[]
self
.
fitnesses
=
[]
for
k
in
range
(
givenSizeOfPopulation
)
:
fitnessGrid
=
np
.
array
([[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
]])
for
i
in
range
(
4
)
:
for
j
in
range
(
4
)
:
fitnessGrid
[
i
,
j
]
=
random
.
randint
(
0
,
10
)
self
.
individuals
.
append
(
Grid
([[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
]],
fitnessGrid
))
def
__str__
(
self
)
:
for
k
in
range
(
self
.
sizeOfPopulation
)
:
print
(
self
.
individuals
[
k
])
# print(self.individuals[k].fitnessGrid)
# print("--------------")
return
(
""
)
def
evaluate
(
self
,
nbrIterations
)
:
""" Fills the fitnesses array
Doesnt return anything
"""
for
k
in
range
(
self
.
sizeOfPopulation
)
:
currentFitness
=
0
for
i
in
range
(
nbrIterations
)
:
print
(
"k, i ="
,
k
,
i
)
finishedGrid
=
single_AI
(
self
.
individuals
[
k
].
grid
,
self
.
individuals
[
k
].
fitnessGrid
)
currentFitness
+=
sum
(
sum
(
finishedGrid
))
self
.
fitnesses
.
append
(
int
(
currentFitness
/
nbrIterations
))
def
select
(
self
,
proportionOfBest
,
proportionOfOthers
)
:
""" Selects the x best individuals from the generation
Selects also y individuals randomly selected
"""
assert
proportionOfBest
+
proportionOfOthers
<
1
nbrOfBest
=
int
((
self
.
sizeOfPopulation
)
*
proportionOfBest
)
nbrOfOthers
=
int
((
self
.
sizeOfPopulation
)
*
proportionOfOthers
)
indexes
=
[]
for
k
in
range
(
nbrOfBest
)
:
currentMaxIndex
=
self
.
fitnesses
.
index
(
max
(
self
.
fitnesses
))
indexes
.
append
(
currentMaxIndex
)
self
.
fitnesses
[
currentMaxIndex
]
=
0
arrayGrid1
=
[[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
]]
for
k
in
range
(
nbrOfOthers
)
:
randomlySelected
=
random
.
randint
(
0
,
self
.
sizeOfPopulation
-
1
)
while
randomlySelected
in
indexes
:
#if already one of the best, try again
randomlySelected
=
random
.
randint
(
0
,
self
.
sizeOfPopulation
-
1
)
indexes
.
append
(
randomlySelected
)
arrayGrid2
=
[[
2
,
8
,
2
,
2
],
[
2
,
2
,
2
,
0
],
[
4
,
2
,
4
,
0
],
[
2
,
2
,
2
,
2
]]
self
.
fitnesses
=
[]
#we reset the fitnesses
arrayGrid3
=
[[
4
,
0
,
0
,
0
],
[
16
,
4
,
2
,
0
],
[
32
,
2
,
8
,
0
],
[
128
,
32
,
2
,
0
]]
#we delete the individuals not selected
for
k
in
range
(
self
.
sizeOfPopulation
)
:
if
k
not
in
indexes
:
self
.
individuals
[
k
]
=
0
return
(
indexes
)
def
mutate
(
self
,
indexes
,
probability
)
:
""" Mutates the selected individuals
indexes = indexes of the selected
Doesnt return anything
"""
for
k
in
indexes
:
if
random
.
randint
(
1
,
int
(
1
/
probability
))
==
1
:
#in this case we add a small noise to the grid, proportional to the tile values
for
i
in
range
(
4
)
:
for
j
in
range
(
4
)
:
tileValue
=
self
.
individuals
[
k
].
grid
[
i
,
j
]
self
.
individuals
[
k
].
fitnessGrid
[
i
][
j
]
+=
random
.
randint
(
-
0.05
*
tileValue
,
0.05
*
tileValue
)
#valeurs random....
def
reproduce
(
self
,
indexes
)
:
""" The reproduction phase
indexes = indexes of the selected
At the moment : randomly mates the selected to fill up the blanks -> TROP VIOLENT ??
Doesnt return anything
"""
assert
len
(
indexes
)
>=
2
numberOfMissing
=
self
.
sizeOfPopulation
-
len
(
indexes
)
indexesOfMissing
=
[]
for
k
in
range
(
self
.
sizeOfPopulation
)
:
if
k
not
in
indexes
:
indexesOfMissing
.
append
(
k
)
for
k
in
indexesOfMissing
:
parent1
=
random
.
choice
(
indexes
)
parent2
=
random
.
choice
(
indexes
)
while
(
parent2
==
parent1
)
:
parent2
=
random
.
choice
(
indexes
)
self
.
individuals
[
k
]
=
Grid
([[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
]]
,
[[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
]])
for
i
in
range
(
4
)
:
for
j
in
range
(
4
)
:
self
.
individuals
[
k
].
fitnessGrid
[
i
][
j
]
=
0.5
*
(
self
.
individuals
[
parent1
].
grid
[
i
,
j
]
+
self
.
individuals
[
parent2
].
grid
[
i
,
j
])
###################################### Variables #########################################
arrayGrid
=
[[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
]]
# MODE = "PLAY"
# MODE = "TEST"
MODE
=
"AI"
MODE
=
"MULTI_AI"
# MODE = "AI"
# MODE = "MULTI_AI"
MODE
=
"GENETIC"
##############################################
######################################
Fonctions ##################################
########
def
evaluateGrid
(
givenGrid
)
:
""" Returns the max value of the grid
"""
return
(
givenGrid
.
max
())
def
single_AI
()
:
myGrid
=
Grid
([[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
]])
def
single_AI
(
givenGrid
,
givenFitnessGrid
)
:
myGrid
=
Grid
(
givenGrid
,
givenFitnessGrid
)
myGrid
.
addNbr
()
myGrid
.
addNbr
()
while
True
:
fitness
Array
=
np
.
array
([[
0
,
0
,
0
,
0
],
#lignes = à 1er move constant
fitness
Grid
=
np
.
array
([[
0
,
0
,
0
,
0
],
#lignes = à 1er move constant
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
]])
...
...
@@ -236,19 +368,19 @@ def single_AI() :
for
k
in
consideredMovesArray
:
for
i
in
range
(
4
)
:
tempGrid
=
Grid
(
myGrid
.
grid
)
tempGrid
=
Grid
(
myGrid
.
grid
,
myGrid
.
fitnessGrid
)
if
tempGrid
.
canSwipe
(
k
)
:
tempGrid
.
swipe
(
k
)
if
tempGrid
.
canSwipe
(
i
)
:
tempGrid
.
swipe
(
i
)
fitness
Array
[
k
][
i
]
=
tempGrid
.
calcFitness
()
fitness
Grid
[
k
][
i
]
=
tempGrid
.
calcFitness
()
maxArray
=
[
0
,
0
,
0
,
0
]
for
k
in
range
(
4
)
:
maxArray
[
k
]
=
max
(
fitness
Array
[
k
])
# maxArray[k] = fitness
Array
[k].mean() #moins bon que le max
maxArray
[
k
]
=
max
(
fitness
Grid
[
k
])
# maxArray[k] = fitness
Grid
[k].mean() #moins bon que le max
#we reverse the array to make sure the default swipe is left and not up
reversedMaxArray
=
maxArray
[::
-
1
]
...
...
@@ -264,9 +396,9 @@ def single_AI() :
elif
direction2
==
3
:
direction2
=
0
#useful for debugging and seeing what is happening:
#
#useful for debugging and seeing what is happening:
# print(myGrid)
# print(fitness
Array
)
# print(fitness
Grid
)
# print(maxArray)
# print(direction2)
# user_input = input()
...
...
@@ -279,14 +411,15 @@ def single_AI() :
break
##############################################
###################################### Main ###########################################
if
MODE
==
"TEST"
:
myGrid
=
Grid
(
arrayGrid3
)
print
(
myGrid
.
canSwipe
(
3
))
# myGrid = Grid(arrayGrid3)
# print(myGrid.canSwipe(3))
myGrid
=
Grid
(
arrayGrid
)
print
(
single_AI
(
myGrid
))
pass
if
MODE
==
"PLAY"
:
...
...
@@ -314,35 +447,49 @@ if MODE == "PLAY" :
pass
print
(
myGrid
.
calcFitness
())
if
MODE
==
"AI"
:
startTime
=
time
.
time
()
finishedGrid
=
single_AI
()
endTime
=
time
.
time
()
print
(
"
\n
----- Partie finie -----"
)
print
(
"Temps écoulé :"
,
int
((
endTime
-
startTime
)
*
1000
),
"ms"
)
print
(
"Valeur max :"
,
evaluateGrid
(
finishedGrid
))
print
(
Grid
(
finishedGrid
))
print
(
"------------------------"
)
if
MODE
==
"MULTI_AI"
:
startTime
=
time
.
time
()
nbrGames
=
150
listScores
=
[[],[]]
for
k
in
range
(
nbrGames
)
:
finishedGrid
=
single_AI
()
maxObtainedValue
=
evaluateGrid
(
finishedGrid
)
if
(
maxObtainedValue
not
in
listScores
[
0
][:])
:
listScores
[
0
].
append
(
maxObtainedValue
)
listScores
[
1
].
append
(
1
)
else
:
listScores
[
1
][
listScores
[
0
].
index
(
maxObtainedValue
)]
+=
1
print
(
"Partie"
,
k
+
1
,
"sur"
,
nbrGames
)
endTime
=
time
.
time
()
print
(
"
\n
----- Parties finies -----"
)
print
(
"Temps écoulé :"
,
int
((
endTime
-
startTime
)
*
1000
),
"ms"
)
print
(
np
.
array
(
listScores
))
print
(
"--------------------------"
)
#plot a bar graph
width
=
30
plt
.
bar
(
listScores
[
0
],
listScores
[
1
],
width
)
plt
.
show
()
# if MODE == "AI" :
# startTime = time.time()
# finishedGrid = single_AI()
# endTime = time.time()
# print(" \n----- Partie finie -----")
# print("Temps écoulé :", int((endTime-startTime)*1000), "ms")
# print("Valeur max :", evaluateGrid(finishedGrid))
# print("Score brut :", sum(sum(finishedGrid)))
# print(Grid(finishedGrid))
# print("------------------------")
# if MODE == "MULTI_AI" :
# startTime = time.time()
# nbrGames = 10
# listScores = [[],[]]
# sumRawScores = 0
# for k in range(nbrGames) :
# finishedGrid = single_AI()
# sumRawScores += sum(sum(finishedGrid))
# maxObtainedValue = evaluateGrid(finishedGrid)
# if (maxObtainedValue not in listScores[0][:]) :
# listScores[0].append(maxObtainedValue)
# listScores[1].append(1)
# else :
# listScores[1][listScores[0].index(maxObtainedValue)] += 1
# print("Partie", k+1, "sur", nbrGames, " - Score brut :", rawScore)
# endTime = time.time()
# print(" \n----- Parties finies -----")
# print("Temps écoulé :", int((endTime-startTime)*1000), "ms")
# print(np.array(listScores))
# print("Temps par unité :", (endTime-startTime)/sumRawScores*1000, "ms")
# print("--------------------------")
# #plot a bar graph
# width = 30
# plt.bar(listScores[0], listScores[1], width)
# plt.show()
if
MODE
==
"GENETIC"
:
myGeneration
=
Generation
(
10
)
myGeneration
.
evaluate
(
10
)
indexes
=
myGeneration
.
select
(
0.3
,
0
)
print
(
indexes
)
print
(
myGeneration
)
myGeneration
.
reproduce
(
indexes
)
print
(
myGeneration
)
2048_ma_fitness.py
0 → 100644
View file @
0486ffd9
import
numpy
as
np
import
random
import
time
import
matplotlib.pyplot
as
plt
# class bcolors:
# HEADER = '\033[95m'
# OKBLUE = '\033[94m'
# OKGREEN = '\033[92m'
# WARNING = '\033[93m'
# FAIL = '\033[91m'
# ENDC = '\033[0m'
# BOLD = '\033[1m'
# UNDERLINE = '\033[4m'
# print (bcolors.OKBLUE + "Some text"
# + bcolors.ENDC)
class
Grid
(
object
)
:
def
__init__
(
self
,
grid
)
:
"""
"""
self
.
grid
=
np
.
array
(
grid
)
def
__str__
(
self
)
:
string
=
""
for
k
in
range
(
4
)
:
for
i
in
range
(
4
)
:
if
self
.
grid
[
k
][
i
]
==
0
:
string
+=
"."
+
" "
else
:
nbrDigits
=
1
power
=
10
while
(
self
.
grid
[
k
][
i
]
//
power
>
0.5
)
:
#0.5 is to avoid numeric noise
nbrDigits
+=
1
power
*=
10
string
+=
str
(
self
.
grid
[
k
][
i
])
+
(
5
-
nbrDigits
)
*
" "
string
+=
"
\n
"
return
string
def
canSwipeBase
(
self
,
grid
)
:
""" returns True if swiping up has an effect
"""
for
columnNbr
in
range
(
4
)
:
currentColumn
=
grid
[:,
columnNbr
]
nbrNonZero
=
np
.
count_nonzero
(
currentColumn
)
if
nbrNonZero
==
0
:
#if empty, go to next
#print("isEmpty")
continue
#warning : if the line is full, it can still be swiped !!
for
lineNbr
in
range
(
3
,
-
1
+
nbrNonZero
,
-
1
)
:
if
currentColumn
[
lineNbr
]
!=
0
:
return
True
for
lineNbr
in
range
(
0
,
3
)
:
if
currentColumn
[
lineNbr
]
==
currentColumn
[
lineNbr
+
1
]
and
currentColumn
[
lineNbr
]
!=
0
:
return
True
return
False
def
canSwipe
(
self
,
direction
)
:
""" returns True if swiping has an effect using canSwipeBase
direction = 0 up, 1 right, 2 down, 3 left
"""
if
direction
==
0
:
return
(
self
.
canSwipeBase
(
self
.
grid
))
elif
direction
==
1
:
rotated
=
np
.
rot90
(
self
.
grid
)
return
(
self
.
canSwipeBase
(
rotated
))
elif
direction
==
2
:
rotated
=
np
.
rot90
(
np
.
rot90
(
self
.
grid
))
return
(
self
.
canSwipeBase
(
rotated
))
elif
direction
==
3
:
rotated
=
np
.
rot90
(
np
.
rot90
(
np
.
rot90
(
self
.
grid
)))
return
(
self
.
canSwipeBase
(
rotated
))
else
:
return
False
def
swipeBase
(
self
,
grid
)
:
""" swipes the grid up, doing all the necessary additions ()
"""
#we start by putting every tile up
for
columnNbr
in
range
(
4
)
:
nbrZeros
=
4
-
np
.
count_nonzero
(
grid
[:,
columnNbr
])
for
lineNbr
in
range
(
4
)
:
counter
=
0
while
(
grid
[
lineNbr
,
columnNbr
]
==
0
)
and
(
counter
<
4
):
counter
+=
1
if
np
.
count_nonzero
(
grid
[
lineNbr
:
4
,
columnNbr
])
!=
0
:
for
remainingLine
in
range
(
lineNbr
,
3
)
:
grid
[
remainingLine
,
columnNbr
]
=
grid
[
remainingLine
+
1
,
columnNbr
]
grid
[
3
,
columnNbr
]
=
0
#now we do the additions
for
lineNbr
in
range
(
3
)
:
if
grid
[
lineNbr
,
columnNbr
]
==
grid
[
lineNbr
+
1
,
columnNbr
]
:
grid
[
lineNbr
,
columnNbr
]
*=
2
for
remainingLine
in
range
(
lineNbr
+
1
,
3
)
:
grid
[
remainingLine
,
columnNbr
]
=
grid
[
remainingLine
+
1
,
columnNbr
]
grid
[
3
,
columnNbr
]
=
0
return
(
grid
)
def
swipe
(
self
,
direction
)
:
""" swipes the grid, doing all the necessary additions (uses swipeBase)
"""
if
direction
==
0
:
self
.
grid
=
self
.
swipeBase
(
self
.
grid
)
elif
direction
==
1
:
rotated
=
np
.
rot90
(
self
.
grid
)
self
.
grid
=
np
.
rot90
(
np
.
rot90
(
np
.
rot90
(
self
.
swipeBase
(
rotated
))))
elif
direction
==
2
:
rotated
=
np
.
rot90
(
np
.
rot90
(
self
.
grid
))
self
.
grid
=
np
.
rot90
(
np
.
rot90
(
self
.
swipeBase
(
rotated
)))
elif
direction
==
3
:
rotated
=
np
.
rot90
(
np
.
rot90
(
np
.
rot90
(
self
.
grid
)))
self
.
grid
=
np
.
rot90
(
self
.
swipeBase
(
rotated
))
else
:
pass
def
addNbr
(
self
)
:
""" adds a number on a empty space
2 with probability 9/10 ; 4 with probability 1/10
doesnt return anything
UN PEU BOURRIN POUR LE MOMENT
"""
#we pick out the random number : 2 or 4
if
random
.
randint
(
1
,
10
)
==
1
:
randomNbr
=
4
else
:
randomNbr
=
2
# we pick a random position for the number
emptyCounter
=
16
-
np
.
count_nonzero
(
self
.
grid
)
randomPosition
=
random
.
randint
(
0
,
emptyCounter
-
1
)
counter
=
0
for
k
in
range
(
4
)
:
for
i
in
range
(
4
)
:
if
self
.
grid
[
k
,
i
]
==
0
:
if
(
counter
==
randomPosition
)
:
self
.
grid
[
k
,
i
]
=
randomNbr
return
#we leave the function
counter
+=
1
def
calcFitness
(
self
)
:
""" Returns the fitness of the grid
"""
# fitnessArray = [[64, 16, 4, 1], #a peu près pareil
# [256, 64, 16, 4],
# [1024, 256, 64, 16],
# [4096, 1024, 256, 64]]
fitnessArray
=
np
.
array
([[
8
,
4
,
2
,
1
],
[
16
,
8
,
4
,
2
],
[
32
,
16
,
8
,
4
],
[
64
,
32
,
16
,
8
]])
## pas nécessairement plus lent...
# fitness = 0
# for k in range(4) :
# for i in range (4) :
# fitness += self.grid[k,i] * fitnessArray[k][i]
fitness
=
sum
(
sum
(
np
.
multiply
(
self
.
grid
,
fitnessArray
)))
return
(
fitness
)
##############################################
arrayGrid1
=
[[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
]]
arrayGrid2
=
[[
2
,
8
,
2
,
2
],
[
2
,
2
,
2
,
0
],
[
4
,
2
,
4
,
0
],
[
2
,
2
,
2
,
2
]]
arrayGrid3
=
[[
4
,
0
,
0
,
0
],
[
16
,
4
,
2
,
0
],
[
32
,
2
,
8
,
0
],
[
128
,
32
,
2
,
0
]]
# MODE = "PLAY"
# MODE = "TEST"
MODE
=
"AI"
MODE
=
"MULTI_AI"
##############################################
def
evaluateGrid
(
givenGrid
)
:
""" Returns the max value of the grid
"""
return
(
givenGrid
.
max
())
def
single_AI
()
:
myGrid
=
Grid
([[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
],
[
0
,
0
,
0
,
0
]])
myGrid
.
addNbr
()
myGrid
.
addNbr
()