n-puzzle
This commit is contained in:
parent
fb540006b2
commit
5f3a00402f
|
@ -0,0 +1,18 @@
|
|||
all: visu_rule
|
||||
|
||||
greedy:
|
||||
@./res_npuzzle-gen.py -s -i 36 5 > test/test.txt
|
||||
@head -1 test/test.txt
|
||||
@./source/main.py -g test/test.txt
|
||||
|
||||
run:
|
||||
@./res_npuzzle-gen.py -s -i 30 4 > test/test.txt
|
||||
@head -1 test/test.txt
|
||||
@./source/main.py test/test.txt
|
||||
|
||||
visu_rule:
|
||||
@./res_npuzzle-gen.py -s -i 50000 3 > test/test.txt
|
||||
@head -1 test/test.txt
|
||||
@./source/main.py test/test.txt
|
||||
@g++ visu/main.cpp visu/ogldev_util.cpp -lglut -lOpenGL -lGLEW
|
||||
@./a.out
|
|
@ -0,0 +1,98 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import random
|
||||
|
||||
def make_puzzle(s, solvable, iterations):
|
||||
def swap_empty(p):
|
||||
idx = p.index(0)
|
||||
poss = []
|
||||
if idx % s > 0:
|
||||
poss.append(idx - 1)
|
||||
if idx % s < s - 1:
|
||||
poss.append(idx + 1)
|
||||
if idx / s > 0 and idx - s >= 0:
|
||||
poss.append(idx - s)
|
||||
if idx / s < s - 1:
|
||||
poss.append(idx + s)
|
||||
swi = random.choice(poss)
|
||||
p[idx] = p[swi]
|
||||
p[swi] = 0
|
||||
|
||||
p = make_goal(s)
|
||||
for i in range(iterations):
|
||||
swap_empty(p)
|
||||
|
||||
if not solvable:
|
||||
if p[0] == 0 or p[1] == 0:
|
||||
p[-1], p[-2] = p[-2], p[-1]
|
||||
else:
|
||||
p[0], p[1] = p[1], p[0]
|
||||
|
||||
return p
|
||||
|
||||
def make_goal(s):
|
||||
ts = s*s
|
||||
puzzle = [-1 for i in range(ts)]
|
||||
cur = 1
|
||||
x = 0
|
||||
ix = 1
|
||||
y = 0
|
||||
iy = 0
|
||||
while True:
|
||||
puzzle[x + y*s] = cur
|
||||
if cur == 0:
|
||||
break
|
||||
cur += 1
|
||||
if x + ix == s or x + ix < 0 or (ix != 0 and puzzle[x + ix + y*s] != -1):
|
||||
iy = ix
|
||||
ix = 0
|
||||
elif y + iy == s or y + iy < 0 or (iy != 0 and puzzle[x + (y+iy)*s] != -1):
|
||||
ix = -iy
|
||||
iy = 0
|
||||
x += ix
|
||||
y += iy
|
||||
if cur == s*s:
|
||||
cur = 0
|
||||
|
||||
return puzzle
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument("size", type=int, help="Size of the puzzle's side. Must be >3.")
|
||||
parser.add_argument("-s", "--solvable", action="store_true", default=False, help="Forces generation of a solvable puzzle. Overrides -u.")
|
||||
parser.add_argument("-u", "--unsolvable", action="store_true", default=False, help="Forces generation of an unsolvable puzzle")
|
||||
parser.add_argument("-i", "--iterations", type=int, default=10000, help="Number of passes")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
random.seed()
|
||||
|
||||
if args.solvable and args.unsolvable:
|
||||
print "Can't be both solvable AND unsolvable, dummy !"
|
||||
sys.exit(1)
|
||||
|
||||
if args.size < 3:
|
||||
print "Can't generate a puzzle with size lower than 2. It says so in the help. Dummy."
|
||||
sys.exit(1)
|
||||
|
||||
if not args.solvable and not args.unsolvable:
|
||||
solv = random.choice([True, False])
|
||||
elif args.solvable:
|
||||
solv = True
|
||||
elif args.unsolvable:
|
||||
solv = False
|
||||
|
||||
s = args.size
|
||||
|
||||
puzzle = make_puzzle(s, solvable=solv, iterations=args.iterations)
|
||||
|
||||
w = len(str(s*s))
|
||||
print "# This puzzle is %s" % ("solvable" if solv else "unsolvable")
|
||||
print "%d" % s
|
||||
for y in range(s):
|
||||
for x in range(s):
|
||||
print "%s" % (str(puzzle[x + y*s]).rjust(w)),
|
||||
print
|
|
@ -0,0 +1,105 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import config
|
||||
from heuristics import *
|
||||
from math import sqrt
|
||||
import numpy as np
|
||||
import copy
|
||||
|
||||
def LEFT(i):
|
||||
return i - 1
|
||||
|
||||
def RIGHT(i):
|
||||
return i + 1
|
||||
|
||||
def UP(i, puzzle_size):
|
||||
return i - puzzle_size
|
||||
|
||||
def DOWN(i, puzzle_size):
|
||||
return i + puzzle_size
|
||||
|
||||
def chunks(l, n):
|
||||
return [l[i:i+n] for i in range(0, len(l), n)]
|
||||
|
||||
class Node(object):
|
||||
def __init__(self, h = 0, g = 0, f = 0, empty_case_index = 0, grid = []):
|
||||
self.h = h
|
||||
self.g = g
|
||||
self.f = f
|
||||
self.index = empty_case_index
|
||||
self.right = None
|
||||
self.left = None
|
||||
self.up = None
|
||||
self.down = None
|
||||
self.size = len(grid)
|
||||
self.sqrt = int(sqrt(len(grid)))
|
||||
self.child = None
|
||||
self.parents = []
|
||||
self.grid = grid
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.f == other.f
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.f < other.f
|
||||
|
||||
def __str__(self):
|
||||
lst = np.matrix(chunks(self.grid, int(sqrt(len(self.grid)))))
|
||||
return str(lst)
|
||||
|
||||
def set_parent(self):
|
||||
self.left = self.swap_left()
|
||||
self.right = self.swap_right()
|
||||
self.up = self.swap_up()
|
||||
self.down = self.swap_down()
|
||||
self.parents = [x for x in [self.right, self.left, self.up, self.down] if x is not None]
|
||||
|
||||
for node in self.parents:
|
||||
node.h = config.heuristic_fn(node.grid)
|
||||
node.size = len(node.grid)
|
||||
node.sqrt = int(sqrt(len(node.grid)))
|
||||
node.child = self
|
||||
node.g = self.g + 1
|
||||
node.f = config.calc_fScore(node.h, node.g)
|
||||
|
||||
def swap_left(self):
|
||||
return self.tile_swap_2_index(LEFT(self.index), self.is_valid_horizontal_move)
|
||||
|
||||
def swap_right(self):
|
||||
return self.tile_swap_2_index(RIGHT(self.index), self.is_valid_horizontal_move)
|
||||
|
||||
def swap_down(self):
|
||||
return self.tile_swap_2_index(DOWN(self.index, self.sqrt), self.is_valid_vertical_move)
|
||||
|
||||
def swap_up(self):
|
||||
return self.tile_swap_2_index(UP(self.index, self.sqrt), self.is_valid_vertical_move)
|
||||
|
||||
def is_valid_vertical_move(self, new_index):
|
||||
return new_index >= 0 and new_index < self.size
|
||||
|
||||
def is_valid_horizontal_move(self, new_index):
|
||||
index = self.index
|
||||
i = index - new_index
|
||||
if (new_index < 0 or new_index > self.size):
|
||||
return False
|
||||
if (index is 0 and i is -1):
|
||||
return True
|
||||
if (index is 1):
|
||||
return True
|
||||
if (((index + 1) % self.sqrt) is 0 and i is -1):
|
||||
return False
|
||||
if (((index + 1) % self.sqrt) is 1 and i is +1):
|
||||
return False
|
||||
return True
|
||||
|
||||
def tile_swap_2_index(self, new_index, valid_move_fn):
|
||||
index = self.index
|
||||
if not valid_move_fn(new_index):
|
||||
return None
|
||||
lst = copy.deepcopy(self.grid)
|
||||
lst[index], lst[new_index] = lst[new_index], lst[index]
|
||||
node = Node()
|
||||
node.grid = lst
|
||||
node.index = new_index
|
||||
return node
|
|
@ -0,0 +1,14 @@
|
|||
import heapq
|
||||
|
||||
class PriorityQueue:
|
||||
def __init__(self):
|
||||
self.elements = []
|
||||
|
||||
def empty(self):
|
||||
return len(self.elements) == 0
|
||||
|
||||
def put(self, item):
|
||||
heapq.heappush(self.elements, (item.f, item))
|
||||
|
||||
def get(self):
|
||||
return heapq.heappop(self.elements)[1]
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
#f score is the sum of the cost to reach that node and the heuristic value of that node.
|
||||
import config
|
||||
from Node import *
|
||||
import numpy as np
|
||||
from PriorityQueue import *
|
||||
|
||||
def chunks(l, n):
|
||||
return [l[i:i+n] for i in range(0, len(l), n)]
|
||||
|
||||
def print_recc(f, elem):
|
||||
if (elem.child):
|
||||
print_recc(f, elem.child)
|
||||
print(np.matrix(chunks(elem.grid, elem.sqrt)))
|
||||
print()
|
||||
f.write(' '.join(['{: >2}'.format(x) for x in elem.grid]))
|
||||
f.write('\n')
|
||||
|
||||
def print_for_visu(process):
|
||||
f = open("test/visu.txt", "w")
|
||||
print_recc(f, process)
|
||||
f.close()
|
||||
|
||||
def a_star_impl(grid, goal, heuristic_ptr):
|
||||
heuristic_ptr= config.heuristic_fn
|
||||
start = Node(h = heuristic_ptr(grid), empty_case_index = grid.index(0), grid = grid)
|
||||
open_set = PriorityQueue()
|
||||
closed_set = PriorityQueue()
|
||||
open_set.put(start)
|
||||
time_complexity = 0
|
||||
size_complexity = 1
|
||||
|
||||
while open_set:
|
||||
process = open_set.get()
|
||||
if process.h is 0 or process.grid is goal:
|
||||
print("Ordered Sequence:")
|
||||
print_for_visu(process)
|
||||
print("Number of moves: {}\n"
|
||||
"Time Complexity: {}\n"
|
||||
"Size Complexity: {}"
|
||||
.format(process.g, time_complexity, size_complexity))
|
||||
return
|
||||
closed_set.put(process)
|
||||
process.set_parent()
|
||||
for node in process.parents:
|
||||
in_close = node.grid in [x.grid for (p, x) in closed_set.elements]
|
||||
in_open = node.grid in [x.grid for (p, x) in open_set.elements]
|
||||
|
||||
if in_close:
|
||||
continue
|
||||
new_g = process.g + 1
|
||||
|
||||
if not in_open:
|
||||
node.g = new_g
|
||||
open_set.put(node)
|
||||
size_complexity += 1
|
||||
else:
|
||||
if (node.g > new_g):
|
||||
node.g = new_g
|
||||
|
||||
node.f = config.calc_fScore(node.h, node.g)
|
||||
time_complexity += 1
|
||||
raise ValueError('No Path Found')
|
|
@ -0,0 +1,8 @@
|
|||
import heuristics
|
||||
|
||||
is_greedy = False
|
||||
goal = []
|
||||
heuristic_fn = None
|
||||
|
||||
def calc_fScore(h, g):
|
||||
return h if is_greedy else g + h
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import math
|
||||
import config
|
||||
|
||||
def hamming_distance(grid):
|
||||
h = 0
|
||||
for i, v in enumerate(grid):
|
||||
if i != config.goal.index(v):
|
||||
h += 1
|
||||
return h
|
||||
|
||||
def manhattan_distance(grid):
|
||||
h = 0
|
||||
size = int(math.sqrt(len(grid)))
|
||||
for i, v in enumerate(grid):
|
||||
if i != config.goal.index(v):
|
||||
curr_col = i % size
|
||||
curr_row = i // size
|
||||
target_col = (config.goal.index(v)) % size
|
||||
target_row = (config.goal.index(v)) // size
|
||||
h += abs(target_col - curr_col) + abs(target_row - curr_row)
|
||||
return h
|
||||
|
||||
def linear_conflict_manhattan_distance(grid):
|
||||
h = manhattan_distance(grid)
|
||||
size = int(math.sqrt(len(grid)))
|
||||
for i, v in enumerate(grid):
|
||||
if i != config.goal.index(v):
|
||||
curr_col = i % size
|
||||
curr_row = i // size
|
||||
target_col = (config.goal.index(v)) % size
|
||||
target_row = (config.goal.index(v)) // size
|
||||
#move left
|
||||
if target_col - curr_col > 0:
|
||||
while (curr_col < target_col):
|
||||
i += 1
|
||||
curr_col = i % size
|
||||
if (grid[v] - 1) // size == target_row:
|
||||
h += 1
|
||||
#move right
|
||||
elif target_col - curr_col < 0:
|
||||
while (curr_col > target_col):
|
||||
i -= 1
|
||||
curr_col = i % size
|
||||
if (grid[v] - 1) // size == target_row:
|
||||
h += 1
|
||||
#move up
|
||||
if target_row - curr_row > 0:
|
||||
while (curr_row < target_row):
|
||||
i += 3
|
||||
curr_row = i // size
|
||||
if (grid[i] - 1) % size == target_col:
|
||||
h += 1
|
||||
#move down
|
||||
elif target_row - curr_row < 0:
|
||||
while (curr_row > target_row):
|
||||
i -= 3
|
||||
curr_row = i // size
|
||||
if (grid[i] - 1) % size == target_col:
|
||||
h += 1
|
||||
return h
|
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import config
|
||||
import re
|
||||
import heuristics
|
||||
from solvable import *
|
||||
from snail import *
|
||||
from a_star import a_star_impl
|
||||
|
||||
|
||||
def make_goal(s):
|
||||
ts = s*s
|
||||
puzzle = [-1 for i in range(ts)]
|
||||
cur = 1
|
||||
x = 0
|
||||
ix = 1
|
||||
y = 0
|
||||
iy = 0
|
||||
while True:
|
||||
puzzle[x + y*s] = cur
|
||||
if cur == 0:
|
||||
break
|
||||
cur += 1
|
||||
if x + ix == s or x + ix < 0 or (ix != 0 and puzzle[x + ix + y*s] != -1):
|
||||
iy = ix
|
||||
ix = 0
|
||||
elif y + iy == s or y + iy < 0 or (iy != 0 and puzzle[x + (y+iy)*s] != -1):
|
||||
ix = -iy
|
||||
iy = 0
|
||||
x += ix
|
||||
y += iy
|
||||
if cur == s*s:
|
||||
cur = 0
|
||||
|
||||
return puzzle
|
||||
|
||||
|
||||
def parse_file(file_name):
|
||||
dict = {}
|
||||
with open(file_name) as f:
|
||||
content = f.read()
|
||||
without_hash = re.sub('#.*', '', content).strip()
|
||||
puzzles = without_hash.split()
|
||||
try:
|
||||
puzzle_size = int(puzzles[0])
|
||||
except:
|
||||
exit("Invalid size: " + puzzles[0])
|
||||
|
||||
puzzles = [ int(puzzle) for puzzle in puzzles[1:]]
|
||||
without_hash = without_hash.splitlines()[1:]
|
||||
|
||||
for line in without_hash:
|
||||
line_length = len(line.split())
|
||||
if (line_length is not puzzle_size):
|
||||
exit("Invalid value in puzzle")
|
||||
return puzzles, puzzle_size
|
||||
|
||||
def parse_arg():
|
||||
parser = argparse.ArgumentParser(description='Faster N-Puzzle you have ever seen')
|
||||
parser.add_argument("-g", "--greedy", default=False, action="store_true",
|
||||
help="Are You a Greedy Bastard?")
|
||||
parser.add_argument("-a", "--algorithm", dest="heuristic",
|
||||
default="manhattan_distance",
|
||||
choices=["hamming_distance", "manhattan_distance", "linear_conflict_manhattan_distance"],
|
||||
help="choose algorithm function")
|
||||
parser.add_argument("path", type=str, default="none", help="input file name")
|
||||
args = parser.parse_args()
|
||||
config.is_greedy = args.greedy
|
||||
config.heuristic_fn = getattr(heuristics, args.heuristic)
|
||||
print("heuristic choosen: {}".format(args.heuristic))
|
||||
return args.path
|
||||
|
||||
def main():
|
||||
grid, size = parse_file(parse_arg())
|
||||
config.goal = make_goal(size)
|
||||
for tile in config.goal:
|
||||
if tile not in grid:
|
||||
exit("Parsing Error")
|
||||
if not solvable(snail_to_ordered_by_ygarrot(grid, config.goal, size)):
|
||||
exit("Error : N-puzzle not solvable !")
|
||||
print("N-puzzle is solvable !")
|
||||
#check if input puzzle go from 0 to N - 1
|
||||
a_star_impl(grid, config.goal, config.heuristic_fn)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,83 @@
|
|||
import numpy as np
|
||||
from math import sqrt
|
||||
|
||||
def chunks(l):
|
||||
n = int(sqrt(len(l)))
|
||||
return np.matrix([l[i:i+n] for i in range(0, len(l), n)])
|
||||
|
||||
def snail_to_ordered_by_ygarrot(snail, goal, size):
|
||||
'''
|
||||
snail_to_ordered and ordered_to_snail functions are
|
||||
historical curiosities left over from earlier days before
|
||||
the advent of N-puzzle solving.
|
||||
'''
|
||||
toto = []
|
||||
ordered = [i + 1 for i in range(size * size)]
|
||||
ordered[-1] = 0
|
||||
|
||||
for i in range(len(ordered)):
|
||||
toto.insert(i, snail[goal.index(ordered[i])])
|
||||
return toto
|
||||
|
||||
|
||||
# def snail_to_ordered(grid):
|
||||
# size = int(math.sqrt(len(grid)))
|
||||
# grid_ret = grid.copy()
|
||||
# for i in range(size // 2):
|
||||
# for j in range(size - 1 - 2 * i):
|
||||
# index = size + j
|
||||
# for k in range(i):
|
||||
# index += (4 * (size - 2 * (k + 1))) + 2
|
||||
# grid_ret[index] = grid[size * (j + i + 2) - i - 1]
|
||||
# for i in range((size - 1) // 2 + (1 - size % 2)):
|
||||
# for j in range(size - 1 - 2 * i):
|
||||
# index = size + (size - 1) + j
|
||||
# for k in range(i):
|
||||
# index += (4 * (size - 2 * (k + 1)))
|
||||
# grid_ret[index] = grid[size * (size - i) - (2 + i) - j]
|
||||
# for i in range((size - 1) // 2):
|
||||
# for j in range(size - 2 - 2 * i):
|
||||
# index = size + 2 * (size - 1) + j
|
||||
# for k in range(i):
|
||||
# index += (4 * (size - 2 * (k + 1))) - 2
|
||||
# grid_ret[index] = grid[size * (size - (2 + i)) - size * j + i]
|
||||
# for i in range((size - 2) // 2 + size % 2):
|
||||
# for j in range(size - 2 - 2 * i):
|
||||
# index = size + 2 * (size - 1) + (size - 2) + j
|
||||
# for k in range(i):
|
||||
# index += (4 * (size - 2 * (k + 1))) - 4
|
||||
# grid_ret[index] = grid[size * (i + 1) + (i + 1) + j]
|
||||
# return grid_ret
|
||||
|
||||
# def ordered_to_snail(grid):
|
||||
# size = int(math.sqrt(len(grid)))
|
||||
# grid_ret = grid.copy()
|
||||
# for i in range(size // 2):
|
||||
# for j in range(size - 1 - 2 * i):
|
||||
# index = size + j
|
||||
# for k in range(i):
|
||||
# index += (4 * (size - 2 * (k + 1))) + 2
|
||||
# grid_ret[size * (j + i + 2) - i - 1] = grid[index]
|
||||
# for i in range((size - 1) // 2):
|
||||
# for j in range(size - 1 - 2 * i):
|
||||
# index = size + (size - 1) + j
|
||||
# for k in range(i):
|
||||
# index += (4 * (size - 2 * (k + 1)))
|
||||
# grid_ret[size * (size - i) - (2 + i) - j] = grid[index]
|
||||
# for i in range((size - 1) // 2):
|
||||
# for j in range(size - 2 - 2 * i):
|
||||
# index = size + 2 * (size - 1) + j
|
||||
# for k in range(i):
|
||||
# index += (4 * (size - 2 * (k + 1))) - 2
|
||||
# grid_ret[size * (size - (2 + i)) - size * j + i] = grid[index]
|
||||
# for i in range((size - 2) // 2):
|
||||
# for j in range(size - 2 - 2 * i):
|
||||
# index = size + 2 * (size - 1) + (size - 2) + j
|
||||
# for k in range(i):
|
||||
# index += (4 * (size - 2 * (k + 1))) - 4
|
||||
# grid_ret[size * (i + 1) + (i + 1) + j] = grid[index]
|
||||
# if size % 2:
|
||||
# grid_ret[len(grid_ret) // 2] = 0
|
||||
# else:
|
||||
# grid_ret[len(grid_ret) // 2 + (size - 4) // 2 + 1] = 0
|
||||
# return grid_ret
|
|
@ -0,0 +1,25 @@
|
|||
import math
|
||||
|
||||
def get_inversions(grid):
|
||||
inversions = 0
|
||||
for i in range(len(grid)):
|
||||
if grid[i] is 0:
|
||||
continue
|
||||
for j in range(i + 1, len(grid)):
|
||||
if grid[j] is not 0 and grid[i] > grid[j]:
|
||||
inversions += 1
|
||||
return inversions
|
||||
|
||||
def odd(n):
|
||||
return (n % 2) != 0
|
||||
|
||||
def solvable(grid):
|
||||
"""Return True if the puzzle is solvable or False if it's not."""
|
||||
size = int(math.sqrt(len(grid)))
|
||||
inversions = get_inversions(grid)
|
||||
if odd(size):
|
||||
return not odd(inversions)
|
||||
else:
|
||||
if odd(grid.index(0)):
|
||||
return not odd(inversions)
|
||||
return odd(inversions)
|
|
@ -0,0 +1,7 @@
|
|||
# This puzzle is solvable
|
||||
5
|
||||
2 18 3 4 5
|
||||
1 0 19 20 6
|
||||
24 14 23 22 7
|
||||
17 16 15 21 8
|
||||
13 12 11 10 9
|
|
@ -0,0 +1,5 @@
|
|||
# This puzzle is solvable
|
||||
3
|
||||
1 2 3
|
||||
8 6 4
|
||||
7 5 0
|
|
@ -0,0 +1,6 @@
|
|||
# This puzzle is solvable
|
||||
4
|
||||
1 2 4 5
|
||||
12 14 0 3
|
||||
11 13 15 6
|
||||
10 9 8 7
|
|
@ -0,0 +1,7 @@
|
|||
# This puzzle is solvable
|
||||
5
|
||||
1 2 3 4 5
|
||||
16 17 18 19 6
|
||||
15 23 20 21 7
|
||||
12 0 22 24 8
|
||||
14 13 11 10 9
|
|
@ -0,0 +1,8 @@
|
|||
# This puzzle is solvable
|
||||
6
|
||||
1 2 3 5 24 6
|
||||
20 21 23 4 0 7
|
||||
19 32 22 34 25 8
|
||||
18 31 33 35 26 9
|
||||
17 30 29 13 27 10
|
||||
16 15 14 12 28 11
|
|
@ -0,0 +1,9 @@
|
|||
# This puzzle is solvable
|
||||
7
|
||||
1 2 3 5 27 6 7
|
||||
24 25 26 4 28 29 8
|
||||
23 40 41 42 43 9 0
|
||||
22 39 48 46 31 30 10
|
||||
21 38 47 45 44 32 11
|
||||
20 37 36 35 34 33 12
|
||||
19 18 17 16 15 14 13
|
|
@ -0,0 +1,10 @@
|
|||
# This puzzle is solvable
|
||||
8
|
||||
1 2 3 4 5 6 7 8
|
||||
28 29 30 31 32 33 34 9
|
||||
27 48 49 50 51 52 35 10
|
||||
26 47 60 62 63 53 36 11
|
||||
25 46 59 61 54 55 37 12
|
||||
24 45 58 57 56 40 38 13
|
||||
23 44 43 42 18 41 39 14
|
||||
22 21 20 19 17 16 0 15
|
|
@ -0,0 +1,11 @@
|
|||
# This puzzle is solvable
|
||||
9
|
||||
1 2 3 4 5 6 7 8 9
|
||||
32 33 34 35 36 37 38 39 10
|
||||
31 56 57 58 59 60 61 40 11
|
||||
30 55 72 73 74 75 62 41 12
|
||||
29 54 71 80 78 76 63 42 13
|
||||
28 53 70 79 77 66 64 43 14
|
||||
27 52 69 68 65 47 46 44 15
|
||||
26 51 50 49 67 21 19 45 16
|
||||
25 24 23 22 48 20 0 18 17
|
|
@ -0,0 +1,5 @@
|
|||
# This puzzle is unsolvable
|
||||
3
|
||||
1 8 2
|
||||
7 4 3
|
||||
0 6 5
|
|
@ -0,0 +1,6 @@
|
|||
# This puzzle is unsolvable
|
||||
4
|
||||
3 1 14 4
|
||||
12 13 2 5
|
||||
11 9 15 6
|
||||
0 10 8 7
|
|
@ -0,0 +1,7 @@
|
|||
# This puzzle is unsolvable
|
||||
5
|
||||
2 1 3 4 5
|
||||
16 17 18 6 8
|
||||
15 24 20 19 21
|
||||
14 23 22 0 10
|
||||
13 12 11 9 7
|
|
@ -0,0 +1,8 @@
|
|||
# This puzzle is unsolvable
|
||||
6
|
||||
2 1 3 4 5 6
|
||||
20 22 0 23 24 7
|
||||
19 21 33 34 25 8
|
||||
31 32 29 35 26 9
|
||||
18 30 28 13 27 10
|
||||
17 16 15 14 12 11
|
|
@ -0,0 +1,9 @@
|
|||
# This puzzle is unsolvable
|
||||
7
|
||||
2 1 3 4 5 6 7
|
||||
24 25 26 27 28 29 8
|
||||
23 41 42 43 30 31 9
|
||||
22 40 39 48 44 32 10
|
||||
21 38 47 46 45 33 11
|
||||
20 37 36 35 34 0 12
|
||||
19 18 17 16 15 14 13
|
|
@ -0,0 +1,10 @@
|
|||
# This puzzle is unsolvable
|
||||
8
|
||||
2 1 3 4 5 6 8 9
|
||||
28 29 30 31 32 33 34 7
|
||||
27 48 49 50 51 0 35 10
|
||||
26 47 60 61 53 52 36 11
|
||||
25 46 59 63 62 54 37 12
|
||||
24 45 58 57 56 55 38 13
|
||||
23 44 43 42 41 40 39 14
|
||||
22 21 20 19 18 17 16 15
|
|
@ -0,0 +1,11 @@
|
|||
# This puzzle is unsolvable
|
||||
9
|
||||
2 1 3 4 5 6 7 8 9
|
||||
32 33 34 35 36 37 38 39 10
|
||||
31 56 57 73 58 60 61 40 11
|
||||
30 55 72 80 59 75 62 41 12
|
||||
29 54 71 79 74 76 63 42 13
|
||||
28 53 70 68 78 77 64 43 14
|
||||
27 52 50 67 0 66 65 44 15
|
||||
26 51 49 69 48 47 46 45 16
|
||||
25 24 23 22 21 20 19 18 17
|
|
@ -0,0 +1,47 @@
|
|||
2 18 3 4 5 1 0 19 20 6 24 14 23 22 7 17 16 15 21 8 13 12 11 10 9
|
||||
2 0 3 4 5 1 18 19 20 6 24 14 23 22 7 17 16 15 21 8 13 12 11 10 9
|
||||
0 2 3 4 5 1 18 19 20 6 24 14 23 22 7 17 16 15 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 0 18 19 20 6 24 14 23 22 7 17 16 15 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 19 20 6 0 14 23 22 7 17 16 15 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 19 20 6 14 0 23 22 7 17 16 15 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 19 20 6 14 23 0 22 7 17 16 15 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 19 20 6 14 23 22 0 7 17 16 15 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 19 0 6 14 23 22 20 7 17 16 15 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 0 19 6 14 23 22 20 7 17 16 15 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 0 18 19 6 14 23 22 20 7 17 16 15 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 23 18 19 6 14 0 22 20 7 17 16 15 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 23 18 19 6 14 16 22 20 7 17 0 15 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 23 18 19 6 14 16 22 20 7 17 15 0 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 23 18 19 6 14 16 0 20 7 17 15 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 23 18 19 6 14 0 16 20 7 17 15 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 23 18 19 6 14 15 16 20 7 17 0 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 23 18 19 6 14 15 16 20 7 0 17 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 23 18 19 6 0 15 16 20 7 14 17 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 23 18 19 6 15 0 16 20 7 14 17 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 0 18 19 6 15 23 16 20 7 14 17 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 0 19 6 15 23 16 20 7 14 17 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 16 19 6 15 23 0 20 7 14 17 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 16 19 6 15 0 23 20 7 14 17 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 16 19 6 15 17 23 20 7 14 0 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 16 19 6 15 17 23 20 7 14 22 0 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 16 19 6 15 17 0 20 7 14 22 23 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 18 0 19 6 15 17 16 20 7 14 22 23 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 0 18 19 6 15 17 16 20 7 14 22 23 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 17 18 19 6 15 0 16 20 7 14 22 23 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 17 18 19 6 15 16 0 20 7 14 22 23 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 17 18 19 6 15 16 23 20 7 14 22 0 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 17 18 19 6 15 16 23 20 7 14 0 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 17 18 19 6 15 16 23 20 7 0 14 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 17 18 19 6 0 16 23 20 7 15 14 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 17 18 19 6 16 0 23 20 7 15 14 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 17 18 19 6 16 23 0 20 7 15 14 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 17 0 19 6 16 23 18 20 7 15 14 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 24 0 17 19 6 16 23 18 20 7 15 14 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 0 24 17 19 6 16 23 18 20 7 15 14 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 16 24 17 19 6 0 23 18 20 7 15 14 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 16 24 17 19 6 15 23 18 20 7 0 14 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 16 24 17 19 6 15 23 18 20 7 14 0 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 16 24 17 19 6 15 0 18 20 7 14 23 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 16 0 17 19 6 15 24 18 20 7 14 23 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 16 17 0 19 6 15 24 18 20 7 14 23 22 21 8 13 12 11 10 9
|
||||
1 2 3 4 5 16 17 18 19 6 15 24 0 20 7 14 23 22 21 8 13 12 11 10 9
|
|
@ -0,0 +1,210 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <GL/glew.h>
|
||||
#include <GL/freeglut.h>
|
||||
#include "ogldev_math_3d.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
|
||||
GLuint VBO;
|
||||
GLuint gridLocation;
|
||||
GLuint nLocation;
|
||||
GLuint timeLocation;
|
||||
|
||||
const char* pVSFileName = "visu/shader.vs";
|
||||
const char* pFSFileName = "visu/shader.fs";
|
||||
const char* pGridFileName = "./test/visu.txt";
|
||||
|
||||
static void RenderSceneCB()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
string grid_file;
|
||||
|
||||
if (!ReadFile(pGridFileName, grid_file))
|
||||
exit(1);
|
||||
static float time = 0.0f;
|
||||
time += 0.03;
|
||||
|
||||
stringstream ssin(grid_file);
|
||||
string token;
|
||||
string token2;
|
||||
int garbage[1024];
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int x = 0, y = 0;
|
||||
while (std::getline(ssin, token, '\n'))
|
||||
{
|
||||
j = 0;
|
||||
stringstream ssin2(token);
|
||||
while (ssin2.good())
|
||||
{
|
||||
ssin2 >> garbage[j];
|
||||
j++;
|
||||
if (j > x)
|
||||
x = j;
|
||||
}
|
||||
i++;
|
||||
if (i > y)
|
||||
y = i;
|
||||
}
|
||||
int n = (int)sqrt(x);
|
||||
int grid[y][x];
|
||||
stringstream ssin3(grid_file);
|
||||
i = 0;
|
||||
while (ssin3.good() && i < x * y)
|
||||
{
|
||||
ssin3 >> grid[(int)(i / x)][i % x];
|
||||
i++;
|
||||
}
|
||||
glUniform1f(timeLocation, time);
|
||||
glUniform1i(nLocation, n);
|
||||
if ((int)time < sizeof(grid) / sizeof(*grid))
|
||||
glUniform1iv(gridLocation, n * n, grid[(int)time]);
|
||||
else
|
||||
exit(1);
|
||||
glEnableVertexAttribArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
|
||||
// first GL_POINT or GL_TRIANGLES
|
||||
// second start of draw
|
||||
// third number of vertices to draw
|
||||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
|
||||
glDisableVertexAttribArray(0);
|
||||
|
||||
glutSwapBuffers();
|
||||
}
|
||||
|
||||
static void InitializeGlutCallbacks(void)
|
||||
{
|
||||
glutDisplayFunc(RenderSceneCB);
|
||||
glutIdleFunc(RenderSceneCB);
|
||||
}
|
||||
|
||||
static void CreateVertexBuffer(void)
|
||||
{
|
||||
Vector3f Vertices[4];
|
||||
Vertices[0] = Vector3f(-1.0f, -1.0f, 0.0f);
|
||||
Vertices[1] = Vector3f(1.0f, -1.0f, 0.0f);
|
||||
Vertices[2] = Vector3f(1.0f, 1.0f, 0.0f);
|
||||
Vertices[3] = Vector3f(-1.0f, 1.0f, 0.0f);
|
||||
|
||||
glGenBuffers(1, &VBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
static void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType)
|
||||
{
|
||||
GLuint ShaderObj = glCreateShader(ShaderType);
|
||||
|
||||
if (ShaderObj == 0)
|
||||
{
|
||||
fprintf(stderr, "Error creating shader type %d\n", ShaderType);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
const GLchar* p[1];
|
||||
p[0] = pShaderText;
|
||||
GLint Lengths[1];
|
||||
Lengths[0] = strlen(pShaderText);
|
||||
glShaderSource(ShaderObj, 1, p, Lengths);
|
||||
glCompileShader(ShaderObj);
|
||||
GLint success;
|
||||
glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
GLchar InfoLog[1024];
|
||||
glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog);
|
||||
fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, InfoLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
glAttachShader(ShaderProgram, ShaderObj);
|
||||
|
||||
}
|
||||
|
||||
static void CompileShaders()
|
||||
{
|
||||
GLuint ShaderProgram = glCreateProgram();
|
||||
|
||||
if (ShaderProgram == 0)
|
||||
{
|
||||
fprintf(stderr, "Error creating shader program\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
string vs;
|
||||
string fs;
|
||||
|
||||
if (!ReadFile(pVSFileName, vs))
|
||||
exit(1);
|
||||
|
||||
if (!ReadFile(pFSFileName, fs))
|
||||
exit(1);
|
||||
|
||||
AddShader(ShaderProgram, vs.c_str(), GL_VERTEX_SHADER);
|
||||
AddShader(ShaderProgram, fs.c_str(), GL_FRAGMENT_SHADER);
|
||||
|
||||
GLint Success = 0;
|
||||
GLchar ErrorLog[1024] = { 0 };
|
||||
|
||||
glLinkProgram(ShaderProgram);
|
||||
glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success);
|
||||
if (Success == 0)
|
||||
{
|
||||
glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog);
|
||||
fprintf(stderr, "Error linking shader program : '%s'\n", ErrorLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
glValidateProgram(ShaderProgram);
|
||||
glGetProgramiv(ShaderProgram, GL_VALIDATE_STATUS, &Success);
|
||||
if (!Success)
|
||||
{
|
||||
glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog);
|
||||
fprintf(stderr, "Invalid shader program '%s'\n", ErrorLog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
glUseProgram(ShaderProgram);
|
||||
gridLocation = glGetUniformLocation(ShaderProgram, "grid");
|
||||
assert(gridLocation != 0xFFFFFFFF);
|
||||
nLocation = glGetUniformLocation(ShaderProgram, "n");
|
||||
assert(nLocation != 0xFFFFFFFF);
|
||||
timeLocation = glGetUniformLocation(ShaderProgram, "time");
|
||||
assert(timeLocation != 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
glutInit(&argc, argv);
|
||||
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
|
||||
glutInitWindowSize(800, 600);
|
||||
glutCreateWindow("N-Puzzle");
|
||||
//glutFullScreen();
|
||||
|
||||
InitializeGlutCallbacks();
|
||||
|
||||
// Must be done after glut is initialized !
|
||||
GLenum res = glewInit();
|
||||
if (res != GLEW_OK)
|
||||
{
|
||||
fprintf(stderr, "Error : '%s'\n", glewGetErrorString(res));
|
||||
return (1);
|
||||
}
|
||||
|
||||
printf("GL version: %s\n", glGetString(GL_VERSION));
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
CreateVertexBuffer();
|
||||
|
||||
CompileShaders();
|
||||
|
||||
glutMainLoop();
|
||||
return (0);
|
||||
}
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
|
||||
Copyright 2010 Etay Meiri
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MATH_3D_H
|
||||
#define MATH_3D_H
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
#else
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include <assimp/vector3.h>
|
||||
#include <assimp/matrix3x3.h>
|
||||
#include <assimp/matrix4x4.h>
|
||||
|
||||
#include "ogldev_util.h"
|
||||
|
||||
#define ToRadian(x) (float)(((x) * M_PI / 180.0f))
|
||||
#define ToDegree(x) (float)(((x) * 180.0f / M_PI))
|
||||
|
||||
float RandomFloat();
|
||||
|
||||
struct Vector2i
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
struct Vector2f
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
|
||||
Vector2f()
|
||||
{
|
||||
}
|
||||
|
||||
Vector2f(float _x, float _y)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Vector3f
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
Vector3f() {}
|
||||
|
||||
Vector3f(float _x, float _y, float _z)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
|
||||
Vector3f(const float* pFloat)
|
||||
{
|
||||
x = pFloat[0];
|
||||
y = pFloat[0];
|
||||
z = pFloat[0];
|
||||
}
|
||||
|
||||
Vector3f(float f)
|
||||
{
|
||||
x = y = z = f;
|
||||
}
|
||||
|
||||
Vector3f& operator+=(const Vector3f& r)
|
||||
{
|
||||
x += r.x;
|
||||
y += r.y;
|
||||
z += r.z;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector3f& operator-=(const Vector3f& r)
|
||||
{
|
||||
x -= r.x;
|
||||
y -= r.y;
|
||||
z -= r.z;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vector3f& operator*=(float f)
|
||||
{
|
||||
x *= f;
|
||||
y *= f;
|
||||
z *= f;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator const float*() const
|
||||
{
|
||||
return &(x);
|
||||
}
|
||||
|
||||
|
||||
Vector3f Cross(const Vector3f& v) const;
|
||||
|
||||
Vector3f& Normalize();
|
||||
|
||||
void Rotate(float Angle, const Vector3f& Axis);
|
||||
|
||||
void Print() const
|
||||
{
|
||||
printf("(%.02f, %.02f, %.02f)", x, y, z);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Vector4f
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
|
||||
Vector4f()
|
||||
{
|
||||
}
|
||||
|
||||
Vector4f(float _x, float _y, float _z, float _w)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
w = _w;
|
||||
}
|
||||
|
||||
void Print(bool endl = true) const
|
||||
{
|
||||
printf("(%.02f, %.02f, %.02f, %.02f)", x, y, z, w);
|
||||
|
||||
if (endl) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
Vector3f to3f() const
|
||||
{
|
||||
Vector3f v(x, y, z);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline Vector3f operator+(const Vector3f& l, const Vector3f& r)
|
||||
{
|
||||
Vector3f Ret(l.x + r.x,
|
||||
l.y + r.y,
|
||||
l.z + r.z);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
inline Vector3f operator-(const Vector3f& l, const Vector3f& r)
|
||||
{
|
||||
Vector3f Ret(l.x - r.x,
|
||||
l.y - r.y,
|
||||
l.z - r.z);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
inline Vector3f operator*(const Vector3f& l, float f)
|
||||
{
|
||||
Vector3f Ret(l.x * f,
|
||||
l.y * f,
|
||||
l.z * f);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
|
||||
inline Vector4f operator/(const Vector4f& l, float f)
|
||||
{
|
||||
Vector4f Ret(l.x / f,
|
||||
l.y / f,
|
||||
l.z / f,
|
||||
l.w / f);
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
|
||||
struct PersProjInfo
|
||||
{
|
||||
float FOV;
|
||||
float Width;
|
||||
float Height;
|
||||
float zNear;
|
||||
float zFar;
|
||||
};
|
||||
|
||||
|
||||
struct OrthoProjInfo
|
||||
{
|
||||
float r; // right
|
||||
float l; // left
|
||||
float b; // bottom
|
||||
float t; // top
|
||||
float n; // z near
|
||||
float f; // z far
|
||||
};
|
||||
|
||||
struct Quaternion
|
||||
{
|
||||
float x, y, z, w;
|
||||
|
||||
Quaternion(float _x, float _y, float _z, float _w);
|
||||
|
||||
void Normalize();
|
||||
|
||||
Quaternion Conjugate();
|
||||
|
||||
Vector3f ToDegrees();
|
||||
};
|
||||
|
||||
|
||||
class Matrix4f
|
||||
{
|
||||
public:
|
||||
float m[4][4];
|
||||
|
||||
Matrix4f()
|
||||
{
|
||||
}
|
||||
|
||||
// constructor from Assimp matrix
|
||||
Matrix4f(const aiMatrix4x4& AssimpMatrix)
|
||||
{
|
||||
m[0][0] = AssimpMatrix.a1; m[0][1] = AssimpMatrix.a2; m[0][2] = AssimpMatrix.a3; m[0][3] = AssimpMatrix.a4;
|
||||
m[1][0] = AssimpMatrix.b1; m[1][1] = AssimpMatrix.b2; m[1][2] = AssimpMatrix.b3; m[1][3] = AssimpMatrix.b4;
|
||||
m[2][0] = AssimpMatrix.c1; m[2][1] = AssimpMatrix.c2; m[2][2] = AssimpMatrix.c3; m[2][3] = AssimpMatrix.c4;
|
||||
m[3][0] = AssimpMatrix.d1; m[3][1] = AssimpMatrix.d2; m[3][2] = AssimpMatrix.d3; m[3][3] = AssimpMatrix.d4;
|
||||
}
|
||||
|
||||
Matrix4f(const aiMatrix3x3& AssimpMatrix)
|
||||
{
|
||||
m[0][0] = AssimpMatrix.a1; m[0][1] = AssimpMatrix.a2; m[0][2] = AssimpMatrix.a3; m[0][3] = 0.0f;
|
||||
m[1][0] = AssimpMatrix.b1; m[1][1] = AssimpMatrix.b2; m[1][2] = AssimpMatrix.b3; m[1][3] = 0.0f;
|
||||
m[2][0] = AssimpMatrix.c1; m[2][1] = AssimpMatrix.c2; m[2][2] = AssimpMatrix.c3; m[2][3] = 0.0f;
|
||||
m[3][0] = 0.0f ; m[3][1] = 0.0f ; m[3][2] = 0.0f ; m[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
Matrix4f(float a00, float a01, float a02, float a03,
|
||||
float a10, float a11, float a12, float a13,
|
||||
float a20, float a21, float a22, float a23,
|
||||
float a30, float a31, float a32, float a33)
|
||||
{
|
||||
m[0][0] = a00; m[0][1] = a01; m[0][2] = a02; m[0][3] = a03;
|
||||
m[1][0] = a10; m[1][1] = a11; m[1][2] = a12; m[1][3] = a13;
|
||||
m[2][0] = a20; m[2][1] = a21; m[2][2] = a22; m[2][3] = a23;
|
||||
m[3][0] = a30; m[3][1] = a31; m[3][2] = a32; m[3][3] = a33;
|
||||
}
|
||||
|
||||
void SetZero()
|
||||
{
|
||||
ZERO_MEM(m);
|
||||
}
|
||||
|
||||
Matrix4f Transpose() const
|
||||
{
|
||||
Matrix4f n;
|
||||
|
||||
for (unsigned int i = 0 ; i < 4 ; i++) {
|
||||
for (unsigned int j = 0 ; j < 4 ; j++) {
|
||||
n.m[i][j] = m[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
inline void InitIdentity()
|
||||
{
|
||||
m[0][0] = 1.0f; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f;
|
||||
m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f;
|
||||
m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f;
|
||||
m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = 0.0f; m[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
inline Matrix4f operator*(const Matrix4f& Right) const
|
||||
{
|
||||
Matrix4f Ret;
|
||||
|
||||
for (unsigned int i = 0 ; i < 4 ; i++) {
|
||||
for (unsigned int j = 0 ; j < 4 ; j++) {
|
||||
Ret.m[i][j] = m[i][0] * Right.m[0][j] +
|
||||
m[i][1] * Right.m[1][j] +
|
||||
m[i][2] * Right.m[2][j] +
|
||||
m[i][3] * Right.m[3][j];
|
||||
}
|
||||
}
|
||||
|
||||
return Ret;
|
||||
}
|
||||
|
||||
Vector4f operator*(const Vector4f& v) const
|
||||
{
|
||||
Vector4f r;
|
||||
|
||||
r.x = m[0][0]* v.x + m[0][1]* v.y + m[0][2]* v.z + m[0][3]* v.w;
|
||||
r.y = m[1][0]* v.x + m[1][1]* v.y + m[1][2]* v.z + m[1][3]* v.w;
|
||||
r.z = m[2][0]* v.x + m[2][1]* v.y + m[2][2]* v.z + m[2][3]* v.w;
|
||||
r.w = m[3][0]* v.x + m[3][1]* v.y + m[3][2]* v.z + m[3][3]* v.w;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
operator const float*() const
|
||||
{
|
||||
return &(m[0][0]);
|
||||
}
|
||||
|
||||
void Print() const
|
||||
{
|
||||
for (int i = 0 ; i < 4 ; i++) {
|
||||
printf("%f %f %f %f\n", m[i][0], m[i][1], m[i][2], m[i][3]);
|
||||
}
|
||||
}
|
||||
|
||||
float Determinant() const;
|
||||
|
||||
Matrix4f& Inverse();
|
||||
|
||||
void InitScaleTransform(float ScaleX, float ScaleY, float ScaleZ);
|
||||
void InitRotateTransform(float RotateX, float RotateY, float RotateZ);
|
||||
void InitRotateTransform(const Quaternion& quat);
|
||||
void InitTranslationTransform(float x, float y, float z);
|
||||
void InitCameraTransform(const Vector3f& Target, const Vector3f& Up);
|
||||
void InitPersProjTransform(const PersProjInfo& p);
|
||||
void InitOrthoProjTransform(const OrthoProjInfo& p);
|
||||
};
|
||||
|
||||
Quaternion operator*(const Quaternion& l, const Quaternion& r);
|
||||
|
||||
Quaternion operator*(const Quaternion& q, const Vector3f& v);
|
||||
|
||||
#endif /* MATH_3D_H */
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
|
||||
Copyright 2011 Etay Meiri
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OGLDEV_TYPES_H
|
||||
#define OGLDEV_TYPES_H
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned char uchar;
|
||||
typedef int32_t i32;
|
||||
typedef uint32_t u32;
|
||||
|
||||
#endif /* OGLDEV_TYPES_H */
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
|
||||
Copyright 2014 Etay Meiri
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "ogldev_util.h"
|
||||
|
||||
bool ReadFile(const char* pFileName, string& outFile)
|
||||
{
|
||||
ifstream f(pFileName);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
if (f.is_open()) {
|
||||
string line;
|
||||
while (getline(f, line)) {
|
||||
outFile.append(line);
|
||||
outFile.append("\n");
|
||||
}
|
||||
|
||||
f.close();
|
||||
|
||||
ret = true;
|
||||
}
|
||||
else {
|
||||
OGLDEV_FILE_ERROR(pFileName);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
char* ReadBinaryFile(const char* pFileName, int& size)
|
||||
{
|
||||
HANDLE f = CreateFileA(pFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (f == INVALID_HANDLE_VALUE) {
|
||||
OGLDEV_FILE_ERROR(pFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
size = GetFileSize(f, NULL);
|
||||
|
||||
if (size == INVALID_FILE_SIZE) {
|
||||
OGLDEV_ERROR("Invalid file size %s\n", pFileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
// wip for tutorial51
|
||||
assert(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
char* ReadBinaryFile(const char* pFileName, int& size)
|
||||
{
|
||||
int f = open(pFileName, O_RDONLY);
|
||||
|
||||
if (f == -1) {
|
||||
OGLDEV_ERROR("Error opening '%s': %s\n", pFileName, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct stat stat_buf;
|
||||
int error = stat(pFileName, &stat_buf);
|
||||
|
||||
if (error) {
|
||||
OGLDEV_ERROR("Error getting file stats: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = stat_buf.st_size;
|
||||
|
||||
char* p = (char*)malloc(size);
|
||||
assert(p);
|
||||
|
||||
int read_len = read(f, p, size);
|
||||
|
||||
if (read_len != size) {
|
||||
OGLDEV_ERROR("Error reading file: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
close(f);
|
||||
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
void OgldevError(const char* pFileName, uint line, const char* format, ...)
|
||||
{
|
||||
char msg[1000];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
VSNPRINTF(msg, sizeof(msg), format, args);
|
||||
va_end(args);
|
||||
|
||||
#ifdef WIN32
|
||||
char msg2[1000];
|
||||
_snprintf_s(msg2, sizeof(msg2), "%s:%d: %s", pFileName, line, msg);
|
||||
MessageBoxA(NULL, msg2, NULL, 0);
|
||||
#else
|
||||
fprintf(stderr, "%s:%d - %s", pFileName, line, msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void OgldevFileError(const char* pFileName, uint line, const char* pFileError)
|
||||
{
|
||||
#ifdef WIN32
|
||||
char msg[1000];
|
||||
_snprintf_s(msg, sizeof(msg), "%s:%d: unable to open file `%s`", pFileName, line, pFileError);
|
||||
MessageBoxA(NULL, msg, NULL, 0);
|
||||
#else
|
||||
fprintf(stderr, "%s:%d: unable to open file `%s`\n", pFileName, line, pFileError);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
long long GetCurrentTimeMillis()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return GetTickCount();
|
||||
#else
|
||||
timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
|
||||
long long ret = t.tv_sec * 1000 + t.tv_usec / 1000;
|
||||
return ret;
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
|
||||
Copyright 2014 Etay Meiri
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OGLDEV_UTIL_H
|
||||
#define OGLDEV_UTIL_H
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "ogldev_types.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool ReadFile(const char* fileName, string& outFile);
|
||||
char* ReadBinaryFile(const char* pFileName, int& size);
|
||||
|
||||
void OgldevError(const char* pFileName, uint line, const char* msg, ... );
|
||||
void OgldevFileError(const char* pFileName, uint line, const char* pFileError);
|
||||
|
||||
#define OGLDEV_ERROR0(msg) OgldevError(__FILE__, __LINE__, msg)
|
||||
#define OGLDEV_ERROR(msg, ...) OgldevError(__FILE__, __LINE__, msg, __VA_ARGS__)
|
||||
#define OGLDEV_FILE_ERROR(FileError) OgldevFileError(__FILE__, __LINE__, FileError);
|
||||
|
||||
#define ZERO_MEM(a) memset(a, 0, sizeof(a))
|
||||
#define ZERO_MEM_VAR(var) memset(&var, 0, sizeof(var))
|
||||
#define ARRAY_SIZE_IN_ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define SNPRINTF _snprintf_s
|
||||
#define VSNPRINTF vsnprintf_s
|
||||
#define RANDOM rand
|
||||
#define SRANDOM srand((unsigned)time(NULL))
|
||||
#else
|
||||
#define SNPRINTF snprintf
|
||||
#define VSNPRINTF vsnprintf
|
||||
#define RANDOM random
|
||||
#define SRANDOM srandom(getpid())
|
||||
#endif
|
||||
|
||||
#define INVALID_UNIFORM_LOCATION 0xffffffff
|
||||
#define INVALID_OGL_VALUE 0xffffffff
|
||||
|
||||
#define SAFE_DELETE(p) if (p) { delete p; p = NULL; }
|
||||
|
||||
#define GLExitIfError \
|
||||
{ \
|
||||
GLenum Error = glGetError(); \
|
||||
\
|
||||
if (Error != GL_NO_ERROR) { \
|
||||
printf("OpenGL error in %s:%d: 0x%x\n", __FILE__, __LINE__, Error); \
|
||||
exit(0); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define GLCheckError() (glGetError() == GL_NO_ERROR)
|
||||
|
||||
long long GetCurrentTimeMillis();
|
||||
|
||||
|
||||
#define ASSIMP_LOAD_FLAGS (aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_JoinIdenticalVertices)
|
||||
|
||||
#endif /* OGLDEV_UTIL_H */
|
||||
|
Binary file not shown.
|
@ -0,0 +1,28 @@
|
|||
#version 330
|
||||
|
||||
uniform float time;
|
||||
uniform int n;
|
||||
vec2 resolution = vec2(800, 600);
|
||||
uniform int grid[1024];
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 uv = (gl_FragCoord.xy-0.5*resolution.xy)/resolution.y;
|
||||
vec3 col = vec3(0);
|
||||
|
||||
vec2 guv = fract(vec2(uv + 0.5 + 1. / float(n)) * float(n));
|
||||
vec2 id = floor(vec2(uv + 0.5 + 1. / float(n)) * float(n));
|
||||
|
||||
float m = 0.;
|
||||
|
||||
if (id.x > 0. && id.x <= float(n) && id.y > 0. && id.y <= float(n))
|
||||
{
|
||||
col.gb = smoothstep(1., float(n), abs(mod(id + time, float(n)) - float(n) / 2.) + 1.);
|
||||
float d = length(guv - 0.5);
|
||||
float dist = length(id) * 10.;
|
||||
float r = mix(.0001, .2, (sin(time) * 0.2 + 1.2) * float(grid[int(float(n) - id.y) * n + int(id.x - 1.)]) / float(n * n));
|
||||
m += 1 - smoothstep(r, r * .1, d);
|
||||
}
|
||||
col.xyz += vec3(m);
|
||||
gl_FragColor = vec4(col,1.0);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#version 330
|
||||
|
||||
layout (location = 0) in vec3 Position;
|
||||
|
||||
uniform float gScale;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(Position.x, Position.y, Position.z, 1.0);
|
||||
}
|
Loading…
Reference in New Issue