summaryrefslogtreecommitdiff
path: root/data/mahjong.lua
blob: a7f0b09411c191108a1ff4ecc59484fbe7ebfe5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
math.randomseed(os.time())
--local debugging = false
if not debugging then
	print = function(...) end
end
--local cam = scene.newcamera({10,10,10},{0,0,0},0)
--print("Hello from mahjong.lua")
--local w = 54
--local h = 90
--local img = video.newiimage(video.R8G8B8,{w,h})

--local tex = video.newtexture("whatever",img)

--[[
	Represent the world as a 3d grid, where each tile covers a 2x2x1 space,
	so that we don't have to worry about half-grids. Each space is either
	"empty", "occupied by tile X" or "tile X"

]]

local tiles = {}
do
	for i = 1,9 do
		tiles[#tiles + 1] = "bamboo" .. tostring(i)
		tiles[#tiles + 1] = "circle" .. tostring(i)
	end
	
	for i = 1,15 do
		tiles[#tiles + 1] = "pinyin" .. tostring(i)
	end

	tiles[#tiles + 1] = "fall"
	tiles[#tiles + 1] = "spring"
	tiles[#tiles + 1] = "summer"
	tiles[#tiles + 1] = "winter"

	tiles[#tiles + 1] = "lotus"
	tiles[#tiles + 1] = "orchid"
	tiles[#tiles + 1] = "peony"
end

local function print_puzzle(puzzle)
	print(debug.traceback())
	for l,layer in ipairs(puzzle.tiles) do
		print("Layer",l)
		local guide1 = {}
		local guide2 = {}
		for i = 1,puzzle.unused_spots.columns do
			guide1[i] = math.floor(i / 10)
			guide2[i] = i % 10
		end
		print("    " .. table.concat(guide1," "))
		print("    " .. table.concat(guide2," "))
		print()
		for i = 1, puzzle.unused_spots.rows do
			local bld = {string.format("%02d  ",i)}
			for j=1,puzzle.unused_spots.columns do
				if puzzle.tiles[l][i][j] then
					bld[#bld + 1] = puzzle.tiles[l][i][j].n
				else
					bld[#bld + 1] = 0
				end
				bld[#bld] = string.format("%2d",bld[#bld])
			end
			print(table.concat(bld," "))
		end
	end
end

function math.round(num)
	if num % 1 > 0.5 then
		return math.ceil(num)
	else
		return math.floor(num)
	end
end

function rep(value,times)
	local ret = {}
	for i = 1,times do
		ret[i] = value
	end
	return unpack(ret)
end

local turtle = {
	columns = 15 * 2,
	rows = 8 * 2,
	layers = 5,
	--First layer
	{
		--First row
		{0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0},
		{0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0},
		--Second row
		{0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0},
		--Third row	
		{0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0},
		{0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0},
		--Fourth row
		{0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0},
		{1,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	1,2,	1,2},
		--Fifth row
		{2,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	2,2,	2,2},
		{0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0},
		--Sixth row
		{0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0},
		{0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0},
		--Seventh row
		{0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0},
		--Eighth row
		{0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0},
		{0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0},
	},
	--Second layer
	{
		--First row
		{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,	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},
		--Second row
		{0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Third row
		{0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Fourth row
		{0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Fifth row
		{0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Sixth row	
		{0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Seventh row	
		{0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Eighth row
		{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,	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},
	},
	--Third layer
	{
		--First row
		{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,	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},
		--Second row
		{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,	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},
		--Third row
		{0,0,	0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Fourth row	
		{0,0,	0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Fifth row
		{0,0,	0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Sixth row
		{0,0,	0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	1,2,	1,2,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		{0,0,	0,0,	0,0,	0,0,	0,0,	2,2,	2,2,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Seventh row
		{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,	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},
		--Eighth row
		{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,	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},
	},
	--Fourth layer
	{
		--First row
		{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,	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},
		--Second row
		{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,	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},
		--Third row
		{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,	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},
		--Fourth row
		{0,0,	0,0,	0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	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,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Fifth row
		{0,0,	0,0,	0,0,	0,0,	0,0,	0,0,	1,2,	1,2,	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,	2,2,	2,2,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Sixth row
		{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,	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},
		--Seventh row
		{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,	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},
		--Eighth row
		{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,	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},
	},
	--Fifth layer
	{
		--First row
		{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,	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},
		--Second row
		{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,	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},
		--Third row
		{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,	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},
		--Fourth row
		{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,	0,0,	0,0,	0,0,	0,0,	0,0,	0,1,	2,0,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Fifth row
		{0,0,	0,0,	0,0,	0,0,	0,0,	0,0,	0,2,	2,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,0,	0,0,	0,0,	0,0,	0,0,	0,0,	0,0},
		--Sixth row
		{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,	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},
		--Seventh row
		{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,	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},
		--Eighth row
		{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,	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},
	}
}

local types = {
	empty = 0,
	tile = 1,
	usedby = 2
}

local current_tile = nil

local tilewidth =  28
local tileheight = 40 
local layeroffx = 8
local layeroffy = -8
local function create_tile(number)
	number = (number % #tiles) + 1
	local tex = video.newtexturefromfile("../data/fulltiles/" .. tiles[number] .. ".png")
	local newtile = {
		tiletype = types.tile,
		iguitexture = gui.newiguiimage({0,0},true,tex),
		rect = {{0,0},{tilewidth,tileheight}},
		n = number
	}
	current_tile = newtile

	return newtile
end
local tileactualx = 32
local tileactualy = 48
local function set_tile_pos(tile,layer,row,column)
	print("Setting a tile to", layer,row,column)
	local x = (row * tilewidth) + (layer * layeroffx)
	local y = (column * tileheight) + (layer * layeroffy)
	tile.iguitexture:move({x,y})
	tile.rect = {{x,y},{x+(tileactualx*2),y+(tileactualy*2)}}
	tile.position = {layer,row,column}
end

--Checks if a tile is free to move
local function is_free(puzzle,tile)
	local layer,col,row = unpack(tile.position)
	--print("Checking if tile at ", layer, row, col , " is free")
	local has_tile_over = false
	for i = layer+1,puzzle.unused_spots.layers do
		for j = col-1,col+1 do
			for k = row - 1, row + 1 do
				--print("Checking if there is a tile at ", i, k, j)
				if puzzle.tiles[i] and puzzle.tiles[i][k] and puzzle.tiles[i][k][j] ~= nil then
					--print("There was!")
					has_tile_over = true	
				end
				if has_tile_over then break end
			end
			if has_tile_over then break end
		end
		if has_tile_over then break end
	end
	if has_tile_over then return false end

	local can_move_left = true
	for i = col-1,0,-1 do
		if not can_move_left then break end
		for j = -1,1 do
			--print("Checking for any tiles at ",layer,row + j,i)
			if puzzle.tiles[layer] and puzzle.tiles[layer][row + j] and puzzle.tiles[layer][row + j][i] ~= nil then
				--print("Cannot move left")
				can_move_left = false
				break
			end
		end
	end
	if can_move_left then return true end

	local can_move_right = true 

	for i = col+1,puzzle.unused_spots.columns do
		if not can_move_right then break end
		for j = -1,1 do
			--print("Checking for any tiles at ",layer,row + j,i)
			if puzzle.tiles[layer] and puzzle.tiles[layer][row + j] and puzzle.tiles[layer][row + j][i] ~= nil then
				--print("Cannot move right")
				can_move_right = false
				break
			end
		end
	end
	
	return can_move_right
end

local function any_free(puzzle)
	local free = {}
	for layer = 1,puzzle.unused_spots.layers do
		for row = 1,puzzle.unused_spots.rows do
			for col = 1,puzzle.unused_spots.columns do
				local tile = puzzle.tiles[layer][row][col]
				if tile then
					print("Found a tile at", layer, row, col)
				end
				if tile and is_free(puzzle,tile) then
					print("Found a free tile at", layer, row, col)
					print("n was", tile.n)
					if free[tile.n] == nil then
						free[tile.n] = 1
					else
						free[tile.n] = free[tile.n] + 1
					end
				end
			end
		end
	end
	for k,v in pairs(free) do
		if v > 1 then
			return true
		end
	end
	return false
end

local function deepcopy(tbl)
	print(debug.traceback())
	print("making a deep copy of",tbl)
	for k,v in pairs(tbl) do print(k,":",v) end
	local ret = {}
	for k,v in pairs(tbl) do
		local key,value
		if type(k) == "table" then
			key = deepcopy(k)
		else
			key = k
		end

		if type(v) == "table" then
			value = deepcopy(v)
		else
			value = v
		end

		ret[key] = value
	end

	return ret
end

--Generates a puzzle
local function gen_puzzle(pattern)
	print("Pattern is", pattern)
	local puz = {
		unused_spots = deepcopy(pattern),
		tiles = {} --Layers
	}
	for l,layer in ipairs(puz.unused_spots) do
		puz.tiles[l] = {}
		for r,row in pairs(layer) do
			puz.tiles[l][r] = {}
		end
	end

	--Returns canfit,layer,row,column if a peice can fit in this row in this puzzle
	local function find_unused_spot(puzzle)
		print("finding unused spots")
		print(debug.traceback())
		local potential_spots = {}
		local layernum = 1

		print("Looking for unused positions in :")
		for l,layer in ipairs(puzzle.unused_spots) do
			print("Layer",l)
			local guide1 = {}
			local guide2 = {}
			for i = 1,puzzle.unused_spots.columns do
				guide1[i] = math.floor(i / 10)
				guide2[i] = i % 10
			end
			--print("    " .. table.concat(guide1," "))
			--print("    " .. table.concat(guide2," "))
			--print()
			for r,row in pairs(layer) do
				local sb = {}
				for c,col in pairs(row) do
					sb[c] = col
				end
				--print(string.format("%02d  ",r) .. table.concat(sb," "))
			end
		end
		print("Continueing...")
				

		for row = 1,puzzle.unused_spots.rows do
			--print("Looking at row", row)
			local from_left = 0
			for col=(puzzle.unused_spots.columns/2),1,-1 do
				--print("Looking at column", col)
				for layer=1,puzzle.unused_spots.layers do
					--print("Looking at layer", layer)
					--print("From_left was", from_left)
					local tel = puzzle.unused_spots[layer][row][col]
					--print("tel was", tel)
					if from_left == 0 and tel == 1 then
						--print("found an unused spot")
						from_left = {layer,row,col}
					--elseif from_left == 0 and tel == 2 then
						----print("Hit no left")
						---- there's not from_left avaliable for this row
						--from_left = -1
						--break
					elseif from_left ~= 0 then 
						--print("found something, breaking...")
						break
					end
				end
				if from_left ~= 0 then break end
			end
			--print("Got from_left")	
			local from_right = 0
			for col=puzzle.unused_spots.columns/2,puzzle.unused_spots.columns,1 do
				for layer=1,puzzle.unused_spots.layers do
					if from_right== 0 and puzzle.unused_spots[layer][row][col] == 1 then
						from_right = {layer,row,col}
					--elseif from_right == 0 and puzzle.unused_spots[layer][row][col] == 2 then
						----Theres no from_right avaliable for this row
						--from_right = -1
						--break

					elseif from_right ~= 0 then break end
				end
				if from_right ~= 0 then break end
			end
			--print("Got from_right")
			--print("from left is", from_left)
			--print("from right is", from_right)
			local spots_same = true
			if type(from_left) == "table" and type(from_right) == "table" then
				--print("Checking if spots same",table.concat(from_left,","),table.concat(from_right,","))
				for i = 1,3 do
					if from_left[i] ~= from_right[i] then
						spots_same = false
						break
					end
				end
			elseif from_left == 0 or from_right == 0 then
				spots_same = false
			end
			--print("Spots_same is", spots_same)
			--print("Looking at same spots")
			if not spots_same then
				if from_left ~= 0 then
					potential_spots[#potential_spots + 1] = from_left
				end
				if from_right ~= 0 then
					potential_spots[#potential_spots + 1] = from_right
				end
			elseif spots_same and type(from_left) == "table" then
				potential_spots[#potential_spots + 1] = from_left
			end
		end
		--print("Found ", #potential_spots, " unused spots...")
		return potential_spots
	end
	--print("Finding an unused spot:")
	local spots = find_unused_spot(puz)
	for spotnum,spot in pairs(spots) do
		--print("Spot", spotnum, ":", spot[1],",",spot[2],",",spot[3])
	end
	--Iterate through integers, putting the same number of each kind of tile on the board.
	local tilenum = 0
	while true do
		local can_place_into = false
		local potential_spots = find_unused_spot(puz)
		print("Number of potential spots is", #potential_spots)
		--print("Potential spots is:")
		--for k,v in pairs(potential_spots) do
			--print(k,":")
			--print("\t",table.concat(v,","))
		--end
		if #potential_spots == 0 then
			print("Potential spots is 0! break!")
			break
		end
		if #potential_spots == 1 then
			--We've generated ourselves into a corner, try again
			print("I want to crash!")
			print("Generated into corner!")
			coroutine.yield()
			local pn = gen_puzzle(pattern)
			return pn
		end
		local numpotspots = #potential_spots
		local rng1 = math.random(1,numpotspots)
		local rng2 = math.random(1,numpotspots-1)
		--print("rng1 is", rng1)
		--print("rng2 is", rng2)
		local spot1 = potential_spots[rng1]
		local spot2 = potential_spots[rng2]
		--if spot1 == spot2 then
			--spot2 = potential_spots[rng2+1]
		--end
		--print("spot1 is", spot1, "(" .. table.concat(spot1,",") .. ")")
		--print("spot2 is", spot2, "(" .. table.concat(spot2,",") .. ")")
		if not spot1 or not spot2 then
			crash()
		end
		local spots_same = true
		for i = 1,3 do
			if spot1[i] ~= spot2[i] then
				spots_same = false
				break
			end
		end
		if not spots_same then
			puz.tiles[spot1[1]][spot1[2]][spot1[3]] = tilenum
			puz.tiles[spot2[1]][spot2[2]][spot2[3]] = tilenum
			
			for i = 0,1 do
				for j = 0,1 do
					local x1,y1,z1 = spot1[1],spot1[2] + i,spot1[3] + j
					local x2,y2,z2 = spot2[1],spot2[2] + i,spot2[3] + j
					puz.unused_spots[x1][y1][z1] = 0
					puz.unused_spots[x2][y2][z2] = 0
				end
			end
			
			for k,v in pairs({spot1,spot2}) do
				--local tile = create_tile(tilenum)
				--set_tile_pos(tile,v[1],v[3],v[2])
				--puz.tiles[v[1]][v[2]][v[3]] = tile
			end
			
			tilenum = tilenum + 101
		end
		coroutine.yield(puz)
	end
	for layer = 1,puz.unused_spots.layers do
		for col = puz.unused_spots.columns,1,-1 do
			for row = 1,puz.unused_spots.rows do
				local tilenum = puz.tiles[layer][row][col]
				if tilenum then
					local tile = create_tile(tilenum)
					set_tile_pos(tile,layer,col,row)
					puz.tiles[layer][row][col] = tile
					coroutine.yield()
				end
			end
		end
	end
	
	return puz
end

for i = 1,10 do
	print(math.round(math.random(1,2)))
end

local puzzle = nil
local e
local co = coroutine.create(function()
	return gen_puzzle(turtle)
end)
local ogt = GAME.tick
local game_generated = false
function GAME.tick()
	print("Running tick...\n")
	if coroutine.status(co) == "suspended" then
		e,puzzle = coroutine.resume(co)
		if not e then
			error(puzzle)
			co = coroutine.create(function()
				return gen_puzzle(turtle)
			end)
		end
	else
		print("After generation, puzzle was", puzzle)
		game_generated = true
	end
	if ogt then
		ogt()
	end
end
--print_puzzle(puzzle)

local xoff = 36
local yoff = 30
local rectx = tilewidth
local recty = tileheight
local selected = nil
local game_has_ended = false
function GAME.onMouseDown(x,y,mouse)
	local possible_tiles = {}
	for layernum,layer in pairs(puzzle.tiles) do
		for rownum,row in pairs(layer) do
			for colnum,tile in pairs(row) do
				local clip = tile.rect
				if x > clip[1][1] and x < clip[2][1] and y > clip[1][2] and y < clip[2][2] then
					possible_tiles[#possible_tiles + 1] = tile
				end
			end
		end
	end

	local toptile = possible_tiles[#possible_tiles]
	if toptile == nil then return end
	local has_removed = false
	-- Check if the tile we selected can move
	if is_free(puzzle,toptile) then
		if selected == nil then
			selected = toptile
			selected.iguitexture:setcolor({255,0,0,255})
		else
			if toptile.n == selected.n and toptile ~= selected then
				toptile.iguitexture:remove()
				selected.iguitexture:remove()
				toptile.iguitexture = nil
				selected.iguitexture = nil
				tl,tc,tr = unpack(toptile.position)
				sl,sc,sr = unpack(selected.position)
				puzzle.tiles[tl][tr][tc] = nil
				puzzle.tiles[sl][sr][sc] = nil
				selected = nil
				has_removed = true
			else
				selected.iguitexture:setcolor({255,255,255,255})
				selected = toptile
				selected.iguitexture:setcolor({255,0,0,255})
			end
		end
	end

	--Check to see if the tile we removed has finished the game
	local numtiles = 0
	if has_removed then
		for layernum,layer in pairs(puzzle.tiles) do
			if numtiles > 0 then break end
			for rownum,row in pairs(layer) do
				if numtiles > 0 then break end
				for columnnum,tile in pairs(row) do
					if tile ~= nil then
						numtiles = numtiles + 1
						break
					end
				end
			end
		end
	else
		numtiles = 1 -- don't finish the game if we didn't remove a tile
	end

	--We're done! End the game!
	if numtiles == 0 then
		game_has_ended = true
	end

	if not any_free(puzzle) and not game_has_ended then
		error("You fail! (no moves left)")
	end

	--::foundtile::
end

local fireworks = {}
local stars = {}
local screenw = scrw()
local screeny = scrh()

print("About to create firework star image")
local starwidth = 3
local starheight = 3
local riseimg= video.newiimage(video.A8R8G8B8,{starwidth,starheight})
for i = starheight - starwidth,1,-1 do
	print("Going through loop, i is",i)
	local color = {255,255,255,255} --alpha = 127 it's not there, alpha = 128 it's there
	riseimg:setPixel({0,i},color,true)
	riseimg:setPixel({1,i-1},color,true)
	riseimg:setPixel({2,i},color,true)
end
local bloomwidth,bloomheight = 100,100
local starimg = video.newiimage(video.A8R8G8B8,{bloomwidth,bloomheight})
for i = -bloomwidth,bloomwidth do
	for j = -bloomheight, bloomheight do
		if math.abs(i^2 + j^2) > 50^2 then
			starimg:setPixel({i + (bloomwidth / 2),j + (bloomheight / 2)},{255,255,255,255},true)
		end
	end
end
local fizzleimg = video.newiimage(video.A8R8G8B8,{3,3})
for i = 0,2 do
	for j = 0,2 do
		fizzleimg:setPixel({i,j},{255,255,255,255},true)
	end
end
local sparkimg = video.newiimage(video.A8R8G8B8,{1,1})
sparkimg:setPixel({0,0},{255,255,255,255},true)
print("Done creating firework star image")
print("video is:")
for k,v in pairs(video) do
	print(k,":",v)
end
local risetex = video.newtexture("rise",riseimg)
local startex = video.newtexture("w/e",starimg)
local fizzletex = video.newtexture("fizz",fizzleimg)
local sparktex = video.newtexture("spark",sparkimg)
local fadetest = video.newiimage(video.A8R8G8B8,{100,100})
for i = 0,99 do
	for j = 0,99 do
		fadetest:setPixel({i,j},{i+j,i+j,i+j,i+j},true)
	end
end
print("video:",video)
for k,v in pairs(video) do
	print(k,":",v)
end

for k,v in pairs(fadetest) do
	print(k,":",v)
end
local fadetex = video.newtexture("test",fadetest)
local left = true
local loadpos = 0
GAME.draw = function()
	if not game_generated then
		if left then
			loadpos = loadpos + 1
		end
		video.drawtexture(fadetex,{screenw/2 - 100,screeny/2 - 5},{{0,0},{loadpos,10}},{255,255,255,255},true)
	end
	for _,v in pairs(fireworks) do
		for i = 1,3 do
			local tcolor = {}
			for k,v in pairs(v.color) do tcolor[k] = v end
			tcolor[4] = 255 - (i * 15)
			video.drawtexture(risetex,{v.x,v.y + i},{{0,0},{starwidth,starheight}},tcolor,true)
		end
	end
	local fw, fh = 20,20
	local stars_to_remove = {}
	for _,v in pairs(stars) do
		local fizzle_in = false 
		for i,j in pairs(v.fizzles) do
			video.drawtexture(fizzletex,{j.x,j.y},{{0,0},{3,3}},v.color,true)
			j.x = j.x + j.vx
			j.y = j.y + j.vy
			if math.random(0,1) == 1 then
				j.vy = j.vy + 1
			end
			if j.y < screenw then
				fizzle_in = true
			end
		end
		if not fizzle_in then
			stars_to_remove[v] = true
		end
	end
	local cursor1 = 1
	local cursor2 = 1
	local starlen = #stars
	while cursor1 < starlen do
		if stars_to_remove[stars[cursor1]] then
			cursor2 = cursor2 + 1
		else
			cursor1 = cursor1 + 1
			cursor2 = cursor2 + 1
		end
		stars[cursor1] = stars[cursor2]
	end
end
local function create_firework()
	local xstart = math.random(50,screenw)
	local rngcolor = {}
	--Only generate "bright" colors:
	--	1 color should be close to 255
	--	1 color should be close to 0
	--	the last color can range from 0 to 255
	local bright = math.random(1,3)
	local dark = math.random(1,2)
	local brightval = math.random(200,255)
	local darkval = math.random(0,55)
	local medval = math.random(0,255)
	local colorset = {brightval,medval,darkval}
	for i = 1,3 do
		local toplace = math.random(1,#colorset)
		rngcolor[i] = colorset[toplace]
		for j = toplace,#colorset do
			colorset[j] = colorset[j + 1]
		end
	end
	rngcolor[4] = 255
	local firework = {
		x = xstart,
		y = screeny,
		color = rngcolor,
		yexp = math.random(150,screeny - 150),
	}
	--firework.img:setcolor(rngcolor)
	fireworks[#fireworks + 1] = firework
end
local function create_star(pos,color)
	--print("creating star at pos")
	for k,v in pairs(pos) do print(k,":",v) end
	--print("with color")
	for k,v in pairs(color) do print(k,":",v) end
	local star = {}
	star.x = pos.x
	star.y = pos.y
	star.color = color
	star.life = 0
	star.fizzles = {}
	for i = 1,10 do
		local ang = math.random(0,2 * math.pi)
		local pow = math.random(0.5,5)
		star.fizzles[i] = {
			x = pos.x,
			y = pos.y,
			vx = math.sin(ang) * pow,
			vy = math.cos(ang) * pow
		}
	end
	stars[#stars + 1] = star
end
local tryimg = gui.newiguiimage({0,0},true,risetex)
local ogt = GAME.tick
function GAME.tick()
	if game_has_ended then
		if math.random() < 0.10 then
			create_firework()
		end
	end
	local fireworks_to_remove = {}
	local crash = false
	local numtoremove = 0
	for _,firework in pairs(fireworks) do
		firework.y = firework.y - 3
		if firework.y < firework.yexp then
			fireworks_to_remove[firework] = true 
			if not firework.exploded then
				create_star({
					x = firework.x,
					y = firework.y
				},firework.color)
				firework.exploded = true
			end
			numtoremove = numtoremove + 1
			crash = true
		end
	end
	local cursor1 = 1
	local cursor2 = 1
	local fwlen = #fireworks
	while cursor1 < fwlen+1 do
		local firework = fireworks[cursor2]
		if fireworks_to_remove[firework] then
			cursor1 = cursor1 + 1
		else
			cursor2 = cursor2 + 1
			cursor1 = cursor1 + 1
		end
		fireworks[cursor2] = fireworks[cursor1]
	end
	if ogt then
		ogt()
	end
end

print("At end of mahjong, GAME.tick is", GAME.tick)