OS dev and where the boot sector is in qemu - qemu

I found this article about writing a simple OS:
https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf
In chapter 3 part 4 there it says that an "X" will be written to the boot sector at: 0x7c00 but, in qemu if you dump the memory you can see its not written to 0x7c00, its written to, 0x7fc8.
Why is this?
What bytes does qemu use for the boot sector?
https://gyazo.com/6dcfaeffea19dfbc6edffa22a1bf0c83
This is the code in the os-dev pdf:
mov ah , 0 x0e
mov bx , the_secret
add bx , 0 x7c00
mov al , [bx]
int 0 x10`
jmp $ ; Jump forever.
the_secret :
db "X "
; Padding and magic BIOS number.
times 510 -( $ - $$ ) db 0
dw 0 xaa55

Related

how can i reverse this disassembly code to c

The disassembly code is this:
movzx ecx, byte ptr [rax] ;
add ecx, 0FFFFFFFEh ;
cmp cl, 2
I guest the code is reversed like this:
if rax - 2 > 2 {
...
Is that right?
and why?
it'll wrap so you have four cases 0-1 , 2-3, 4 (=2) , >4
may be they've used OF check to distinct

Decompiling 8051 binary, read from EEPROM

I'm trying to decompile the firmware of a Logitech Freedom 2.4 Cordless Joystick. I've managed to get something of the EEPROM. (here)
The EEPROM that is used is the Microchip 25AA320, which is a 32Kbit SPI-EEPROM. The MCU is a nRF24E1G , that contains a 8051 MCU.
The ROM should be 4096 bytes, so I think that my reading program looped over it self 4 times.
I managed to extract a 4kB ROM (here), but the start of the file doesn't look clean.
I loaded both files into IDA Pro and Ghidra and selected the 8051 processor. They don't generate anything useful.
Could anyone help me decompiling this ROM?
I used this Arduino Sketch to dump the rom.
Together with this python script
## Author: Arpan Das
## Date: Fri Jan 11 12:16:59 2019 +0530
## URL: https://github.com/Cyberster/SPI-Based-EEPROM-Reader-Writer
## It listens to serial port and writes contents into a file
## requires pySerial to be installed
import sys
import serial
import time
start = time.time()
MEMORY_SIZE = 4096 # In bytes
serial_port = 'COM5'
baud_rate = 115200 # In arduino, Serial.begin(baud_rate)
write_to_file_path = "dump.rom"
output_file = open(write_to_file_path, "wb")
ser = serial.Serial(serial_port, baud_rate)
print("Press d for dump ROM else CTRL+C to exit.")
ch = sys.stdin.read(1)
if ch == 'd':
ser.write('d')
for i in range(MEMORY_SIZE/32): # i.e. MEMORY_SIZE / 32
# wait until arduino response with 'W' i.e. 1 byte of data write request
while (ser.read() != 'W'): continue
ser.write('G') # sends back write request granted signal
for j in range(32):
byte = ser.read(1);
output_file.write(byte);
print(str(MEMORY_SIZE - (i * 32)) + " bytes remaining.")
print '\nIt took', time.time()-start, ' seconds.'
This is what I did, the next part left is for you. My machine is a Win10 notebook, however I used unix tools because they are so capable.
First of all, I divided the 16KB dump into four 4KB parts. The first one was different from the other three. And the provided 4KB dump is different to all of these parts. I did not investigate this further, and simply took one of the other three parts that are all equal.
$ split -b 4K LogitechFreedom2.4CordlessJoystick.rom part
$ cmp partaa partab
partaa partab differ: byte 1, line 1
$ cmp partab partac
$ cmp partac partad
$ cmp dump.rom partaa
dump.rom partaa differ: byte 9, line 1
$ cmp dump.rom partab
dump.rom partab differ: byte 1, line 1
From the microcontroller's data sheet I learned that the EEPROM contents has a header of at least 3 bytes (chapter 10.2 at page 61).
These bytes are:
0b Version = 00, Reserved = 00, SPEED = 0.5MHz, XO_FREQ = 16MHz
03 Offset to start of user program = 3
0f Number of 256 bytes block = 15
The last entry seems to be off by one, because there seems to be code in the 16th block, too.
Anyway, these bytes look decent, so I cut the first 3 bytes.
$ dd if=partad of=rom.bin bs=1 skip=3
4093+0 records in
4093+0 records out
4093 bytes (4,1 kB, 4,0 KiB) copied, 0,0270132 s, 152 kB/s
$ dd if=partad of=head.bin bs=1 count=3
3+0 records in
3+0 records out
3 bytes copied, 0,0043809 s, 0,7 kB/s
$ od -Ax -t x1 rom.bin > rom.hex
$ od -Ax -t x1 head.bin > head.hex
The hex files are nice for loading them into an editor and look around.
I loaded the remaining 4093 bytes into a disassembler I once wrote and peeked around a bit. It looks promising, so I think you can go on without me now:
C0000: ljmp C0F54
C0003: setb 021H.2
reti
C000B: xch a,r5
inc r6
xrl a,r6
mov a,#0B2H
movc a,#a+pc
movx #r1,a
mov r7,a
setb 021H.2
reti
C0F54: mov psw,#000H
mov sp,#07BH
mov r0,#0FFH
mov #r0,#000H
djnz r0,C0F5C
ljmp C0C09

Procedures with floating points breaking

; Author:
; Date:
; This is the Visual Studio 2012 version
; Preprocessor directives
.586 ; use the 80586 set of instructions
.MODEL FLAT ; use the flat memory model (only 32 bit addresses, no segment:offset)
; External source files
INCLUDE io.h ; header file for input/output
INCLUDE fio.h ; header file for floating point conversions to and from ASCII
; Stack configuration
.STACK 4096 ; allocate 4096 bytes for the stack
; Named memory allocation and initialization
; Use REAL4 for floating point values
.DATA
prompt1 BYTE "Enter circumference: ", 0 ; Basic prompt
string BYTE 40 DUP (?)
BoxLabel1 BYTE "The radius is "
radius BYTE 12 DUP (?), 0
msg1 BYTE "The circle circumference is: ", 0ah
circumf2 BYTE 12 DUP (?), 0ah
msg2 BYTE "The circle area is: ", 0ah
area2 BYTE 12 DUP (?), 0
radiusInput REAL4 1.0
pi REAL4 3.14
two REAL4 2.0
areA REAL4 1.0
circumf REAL4 1.0
; procedure definitions
.CODE
_MainProc PROC
;************ INPUT *************
input prompt1, string, 40 ; read ASCII characters
atof radiusInput, string ; Convert (ASCII TO FLOAT) macro
;********************************
finit
push radiusInput
call findCircumf ; BREAKS HERE!!!!
; call findArea
;done:
;************ OUTPUT ************
ftoa radius, radiusInput
ftoa area2, areA
ftoa circumf2, circumf
output BoxLabel1, msg1
;********************************
;*********** CLEAN-UP ***********
mov EAX, 0 ; exit with return code 0
ret
;********************************
_MainProc ENDP
;##################### findCircumf PROCEDURE ##################
findCircumf PROC
; ******** CIRCUMFERENCE ********
; Formula 2*Pi*R
fld two ; ST(0) has 2.0
fld pi ; ST(0) has 3.14 ST(1) 2.0
fmul st(0), st(1) ; ST(0) has 6.28 2*Pi
fld radiusInput ; ST(0) has radius input (3.5) ST(1) has 6.28
fmul ST(0), ST(1) ; ST(0) has 21.98 2*Pi*R
fst circumf
;********************************
findCircumf ENDP
;###################### findArea PROCEDURE #####################
findArea PROC
;************ AREA **************
; Forumla R*R*Pi
fld radiusInput ; ST(0) has radius input (3.5)
fmul st(0), st(0) ; ST(0) has 12.25 R*R (or R^2)
fld pi ; ST(0) has 3.14 ST(1) has 12.25
fmul st(0), st(1) ; ST(0) has 38.465 R*R*Pi
fstp areA ; areA has 38.465
;********************************
findArea ENDP
END ; end of source code
Breaks at call findCircumf with error list saying
windows32.exe has triggered a breakpoint.
The thread 0x1570 has exited with code 0 (0x0).
The program '[628] windows32.exe' has exited with code 0 (0x0).
I know I did something wrong. I am assuming it has to do with my return.
In the procedure the reurn value is in ST(0). I am not sure what I did wrong, I am using floating points.
1.) First of all there is no return statements at the end of the procedure(s).
2.) Since I am using floating point AND STACK I put finit before each procedure call.
3.) I needed to establish a stack frame in the beginning of each procedure
push ebp ; save base pointer
mov ebp, esp ; establish stack frame
push ebx ; save EBX
4.) Pop the registers from the stack frame before the return on each procedure
pop ebx ; restore EBX
pop ebp ; restore EBP
ret ; return
Those things fixed my problem.

Variable initialization in as8088

I'm currently writing a function that should basically just write characters from a string into variables.
When performing test prints my variables seem fine. But when I attempt to print the first variable assigned(inchar) outside of the function it returns a empty string, but the second variable (outchar) seems to return fine. Am I somehow overwriting the first variable?
This is my code:
_EXIT = 1
_READ = 3
_WRITE = 4
_STDOUT = 1
_STDIN = 1
_GETCHAR = 117
MAXBUFF = 100
.SECT .TEXT
start:
0: PUSH endpro2-prompt2
PUSH prompt2
PUSH _STDOUT
PUSH _WRITE
SYS
ADD SP,8
PUSH 4
PUSH buff
CALL getline
ADD SP,4
!!!!!!!!!
PUSH buff
CALL gettrans
ADD SP,4
ADD AX,1 !gives AX an intial value to start loop
1: CMP AX,0
JE 2f
PUSH endpro-prompt1
PUSH prompt1
PUSH _STDOUT
PUSH _WRITE
SYS
ADD SP,8
PUSH MAXBUFF
PUSH buff
CALL getline
ADD SP,2
!PUSH buff
!CALL translate
!ADD SP,4
JMP 1b
2: PUSH 0 ! exit with normal exit status
PUSH _EXIT
SYS
getline:
PUSH BX
PUSH CX
PUSH BP
MOV BP,SP
MOV BX,8(BP)
MOV CX,8(BP)
ADD CX,10(BP)
SUB CX,1
1: CMP CX,BX
JE 2f
PUSH _GETCHAR
SYS
ADD SP,2
CMPB AL,-1
JE 2f
MOVB (BX),AL
INC BX
CMPB AL,'\n'
JNE 1b
2: MOVB (BX),0
MOV AX, BX
SUB AX,8(BP)
POP BP
POP CX
POP BX
RET
gettrans:
PUSH BX
PUSH BP
MOV BP,SP
MOV BX,6(BP) !Store argument in BX
MOVB (inchar),BL ! move first char to inchar
1: INC BX
CMPB (BX),' '
JE 1b
MOVB (outchar),BL !Move char seperated by Space to outchar
MOV AX,1 !On success
POP BP
POP BX
RET
.SECT .BSS
buff:
.SPACE MAXBUFF
.SECT .DATA
prompt1:
.ASCII "Enter a line of text: "
endpro:
prompt2:
.ASCII "Enter 2 characters for translation: "
endpro2:
outchar:
.BYTE 0
inchar:
.BYTE 0
charct:
.BYTE 0
wordct:
.BYTE 0
linect:
.BYTE 0
inword:
.BYTE 0
This is the code used to test print
PUSH 1 ! print that byte
PUSH inchar
PUSH _STDOUT
PUSH _WRITE
SYS
ADD SP,8
CALL printnl !function that prints new line
PUSH 1 ! print that byte
PUSH outchar
PUSH _STDOUT
PUSH _WRITE
SYS
CALL printnl
ADD SP,8
There seem to be a number of as88 8088 simulator environments. But I noticed on many of the repositories of code this bug mentioned:
1. The assembler requires sections to be defined in the following order:
TEXT
DATA
BSS
After the first occurrences, remaining section directives may appear in any order.
I'd recommend in your code to move the BSS section after DATA in the event your as88 environment has a similar problem.
In your original code you had lines like this:
MOV (outchar),BX
[snip]
MOV (inchar),BX
You defined outchar and inchar as bytes. The 2 lines above move 2 bytes (16-bits) from the BX register to both one byte variables. This will cause the CPU to write the extra byte into the next variable in memory. You'd want to explicitly move a single byte. Something like this might have been more appropriate:
MOVB (outchar),BL
[snip]
MOVB (inchar),BL
As you will see this code still has a bug as I mention later in this answer. To clarify - the MOVB instruction will move a single byte from BL and place it into the variable.
When you do a SYS call for Write you need to pass the address of the buffer to print, not the data in the buffer. You had 2 lines like this:
PUSH (inchar)
[snip]
PUSH (outchar)
The parentheses say to take the value in the variables and push them on the stack. SYS WRITE requires the address of the characters to display. The code to push their addresses should look like:
PUSH inchar
[snip]
PUSH outchar
gettrans function has a serious flaw in handling the copy of a byte from one buffer to another. You have code that does this:
MOV BX,6(BP) !Store argument in BX
MOVB (inchar),BL ! move first char to inchar
1: INC BX
CMPB (BX),' '
JE 1b
MOVB (outchar),BL !Move char seperated by Space to outchar
MOV BX,6(BP) properly places that buffer address passed as an argument and puts it into BX. There appears to be a problem with the lines that look like:
MOVB (inchar),BL ! move first char to inchar
This isn't doing what the comment suggests it should. The line above moves the lower byte (BL) of the buffer address in BX to the variable inchar . You want to move the byte at the memory location pointed to by BX and put it into inchar. Unfortunately on the x86 you can't move the data from one memory operand to another directly. To get around this you will have to move the data from the buffer pointed to by BX into a temporary register (I'll choose CL) and then move that to the variable. The code could look like this:
MOVB CL, (BX)
MOVB (inchar),CL ! move first char to inchar
You then have to do the same for outchar so the fix in both places could look similar to this:
MOV BX,8(BP) !Store argument in BX
MOVB CL, (BX)
MOVB (inchar),CL ! move first char to inchar
1: INC BX
CMPB (BX),' '
JE 1b
MOVB CL, (BX)
MOVB (outchar),CL ! move second char to outchar
The instruction MOV (inchar),BX stores register BX to the memory location labelled inchar.
However, inchar has been defined as a .BYTE, but BX is a 16-bit register, (2 bytes,) so you are writing not only inchar but also outchar.
The only reason why it appears to work in the beginning is because the 8088 is a low-endian architecture, so the low-order byte of BX is being stored first, while the high-order byte follows.
So, try MOV (inchar),BL

Code Golf: Triforce

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
This is inspired by/taken from this thread: http://www.allegro.cc/forums/thread/603383
The Problem
Assume the user gives you a numeric input ranging from 1 to 7. Input should be taken from the console, arguments are less desirable.
When the input is 1, print the following:
***********
*********
*******
*****
***
*
Values greater than one should generate multiples of the pattern, ending with the one above, but stacked symmetrically. For example, 3 should print the following:
*********** *********** ***********
********* ********* *********
******* ******* *******
***** ***** *****
*** *** ***
* * *
*********** ***********
********* *********
******* *******
***** *****
*** ***
* *
***********
*********
*******
*****
***
*
Bonus points if you print the reverse as well.
*********** ***********
********* *********
******* *******
***** *****
*** ***
* *
***********
*********
*******
*****
***
*
*
***
*****
*******
*********
***********
* *
*** ***
***** *****
******* *******
********* *********
*********** ***********
Can we try and keep it to one answer per language, that we all improve on?
Assembler, 165 bytes assembled
Build Instructions
Download A86 from here
Add a reference to the A86 executable into your DOS search path
Paste the code below into a text file (example: triforce.asm)
Invoke the assembler: a86 triforce.asm
This will create a .COM file called triforce.com
Type triforce to run
This was developed using the standard WinXP DOS box (Start->Programs->Accessories->Command Prompt). It should work with other DOS emulators.
Assemble using A86 and requires WinXP DOS box to run the .COM file it produces. Press 'q' to exit, keys 1-7 to draw the output.
l20:mov ah,7
int 21h
cmp al,'q'
je ret
sub al,'0'
cmp al,1
jb l20
cmp al,7
ja l20
mov [l0-1],al
mov byte ptr [l7+2],6
jmp $+2
mov ah,2
mov ch,0
mov bh,3
l0:mov bl,1
l1:mov dh,0
l3:cmp dh,ch
je l2
mov dl,32
int 21h
inc dh
jmp l3
ret
l2:mov dh,bh
l6:mov cl,12
l5:mov dl,42
cmp cl,bl
ja l4
mov dl,32
cmp dh,1
je l21
l4:int 21h
dec cl
jnz l5
l21:dec dh
jnz l6
mov dl,10
int 21h
mov dl,13
int 21h
l10:inc ch
l9:add bl,2
l7:cmp ch,6
jne l1
l13:add byte ptr [l7+2],6
l11:dec bh
l12:cmp bh,0
jne l0
xor byte ptr [l0+1],10
xor byte ptr [l9+1],40
xor byte ptr [l10+1],8
xor byte ptr [l13+1],40
sub byte ptr [l7+2],12
mov dh,[l0-1]
inc dh
xor [l12+2],dh
xor byte ptr [l11+1],8
xor byte ptr [l1+1],1
inc bh
cmp byte ptr [l0+1],11
je l0
jmp l20
It uses lots of self-modifying code to do the triforce and its mirror, it even modifies the self-modifying code.
GolfScript - 43 chars
~:!6*,{:^' '
*'*'12*' '
^6%.+)*+
-12>!^
6/-*
n}
/
~:!6*,{:^' '*'*'12*' '^6%.+)*+-12>!^6/-*n}/
48 Chars for the bonus
~:!6*,.-1%+{
:^' '*'*'12
*' '^6%.+
)*+-12>
!^6/-
*n}
/
~:!6*,.-1%+{:^' '*'*'12*' '^6%.+)*+-12>!^6/-*n}/
Python - 77 Chars
n=input()
for k in range(6*n):print' '*k+('*'*12+' '*(k%6*2+1))[-12:]*(n-k/6)
n=input()
for k in range(6*n):j=1+k%6*2;print' '*k+('*'*(12-j)+' '*j)*(n-k/6)
89 Chars for the bonus
n=input();R=range(6*n)
for k in R+R[::-1]:print' '*k+('*'*11+' '*11)[k%6*2:][:12]*(n-k/6)
114 Chars Version just using string replacements
u,v=' *';s=(v*11+u)*input()
while s.strip():print s;s=u+s.replace(*((v*2+u,u*3),(v*1+u*10,v*11))[' * 'in s])[:-2]
Unk Chars all in one statement, should work w/ 2.x and 3.x. The enumerate() is to allow the single input() to work for both places you need to use it.
print ('\n'.join('\n'.join(((' '*(6*n))+' '.join(('%s%s%s'%(' '*(5-x),'*'*(2*x+1),' '*(5-x)) for m in range(i + 1)))) for x in range(5,-1,-1)) for n, i in enumerate(range(int(input())-1,-1,-1))))
Yet Another Method
def f(n): print '\n'.join(' '*6*(n-r)+(' '*(5-l)+'*'*(l*2+1)+' '*(5-l)+' ')*r for r in xrange(1, n+1) for l in xrange(6))
f(input())
Ruby - 74 Chars
(6*n=gets.to_i).times{|k|puts' '*k+('*'*(11-(j=k%6*2))+' '*(j+1))*(n-k/6)}
COBOL - 385 Chars
$ cobc -free -x triforce.cob && echo 7| ./triforce
PROGRAM-ID.P.DATA DIVISION.WORKING-STORAGE SECTION.
1 N PIC 9.
1 M PIC 99.
1 value '0100***********'.
2 I PIC 99.
2 K PIC 99.
2 V PIC X(22).
2 W PIC X(99).
PROCEDURE DIVISION.ACCEPT N
COMPUTE M=N*6
PERFORM M TIMES
DISPLAY W(1:K)NO ADVANCING
PERFORM N TIMES
DISPLAY V(I:12)NO ADVANCING
END-PERFORM
DISPLAY ''
ADD 2 TO I
IF I = 13 MOVE 1 TO I ADD -1 TO N END-IF
ADD 1 TO K
END-PERFORM.
K could be returned to outside the group level. An initial value of zero for a numeric with no VALUE clause is compiler-implementation dependent, as is an initial value of space for an alpha-numeric field (W has been cured of this, at no extra character cost). Moving K back would save two characters. -free is compiler-dependant as well, so I'm probably being over-picky.
sed, 117 chars
s/$/76543210/
s/(.).*\1//
s/./*********** /gp
:
s/\*(\**)\*/ \1 /gp
t
:c
s/\* {11}\*/ ************/
tc
s/\* / /p
t
Usage: $ echo 7 | sed -rf this.sed
First attempt; improvements could probably be made...
Ruby 1.9 - 84 characters :
v=gets.to_i
v.times{|x|6.times{|i|puts' '*6*x+(' '*i+'*'*(11-2*i)+' '*i+' ')*(v-x)}}
Perl - 72 chars
die map$"x$_.("*"x(12-($l=1+$_%6*2)).$"x$l)x($n-int$_/6).$/,0..6*($n=<>)
78 chars
map{$l=$_%6*2;print$"x$_,("*"x(11-$l).$"x$l.$")x($n-int$_/6),$/}0..6*($n=<>)-1
87 chars
$n=<>;map{$i=int$_/6;$l=$_%6*2;print$"x$_,("*"x(11-$l).$"x$l.$")x($n-$i),$/}(0..6*$n-1)
97 chars
$n=<>;map{$i=int$_/6;$l=$_%6;print$"x(6*$i),($"x$l."*"x(11-2*$l).$"x$l.$")x($n-$i),$/}(0..6*$n-1)
108 chars
$n=<>;map{$i=int$_/6;$l=$_%6;print ""." "x(6*$i),(" "x$l."*"x(11-2*$l)." "x$l." ")x($n-$i),"\n";}(0..6*$n-1)
Powershell, 78 characters
0..(6*($n=read-host)-1)|%{" "*$_+("*"*(12-($k=1+$_%6*2))+" "*$k)*(.4+$n-$_/6)}
Bonus, 92 characters
$a=0..(6*($n=read-host)-1)|%{" "*$_+("*"*(12-($k=1+$_%6*2))+" "*$k)*(.4+$n-$_/6)}
$a
$a|sort
The output is stored in an array of strings, $a, and the reverse is created by sorting the array. We could, of course, just reverse the array, but it would be more characters to type :)
Haskell - 131 138 142 143 Chars
(⊗)=replicate
z o=[concat$(6*n+m)⊗' ':(o-n)⊗((11-m-m)⊗'*'++(1+m+m)⊗' ')|n<-[0..o-1],m<-[0..5]]
main=getLine>>=mapM_ putStrLn.z.read
This one is longer (146 148 chars) at present, but an interesting, alternate line of attack:
(⊗)=replicate
a↑b|a>b=' ';_↑_='*'
z o=[map(k↑)$concat$(6*n)⊗' ':(o-n)⊗"abcdefedcba "|n<-[0..o-1],k<-"abcdef"]
main=getLine>>=mapM_ putStrLn.z.read
FORTRAN - 97 Chars
Got rid of the #define and saved 8 bytes thanks to implict loops!
$ f95 triforce.f95 -o triforce && echo 7 | ./triforce
READ*,N
DO K=0,N*6
M=2*MOD(K,6)
PRINT*,(' ',I=1,K),(('*',I=M,10),(' ',I=0,M),J=K/6+1,N)
ENDDO
END
125 bytes for the bonus
READ*,N
DO L=1,N*12
K=L+5
If(L>N*6)K=N*12-L+6
M=2*MOD(K,6)
PRINT"(99A)",(32,I=7,K),((42,I=M,10),(32,I=0,M),J=K/6,N)
ENDDO
END
FORTRAN - 108 Chars
#define R REPEAT
READ*,N
DO I=0,6*N
J=MOD(I,6)*2
PRINT*,R(' ',I)//R(R('*',11-J)//R(' ',J+1),N-I/6)
ENDDO
END
JavaScript 1.8 - SpiderMonkey - 118 chars
N=readline()
function f(n,c)n>0?(c||' ')+f(n-1,c):''
for(i=0;i<N*6;i++)print(f(i)+f(N-i/6,f(11-(z=i%6*2),'*')+f(z+1)))
w/ bonus - 151 chars
N=readline()
function f(n,c)n>0?(c||' ')+f(n-1,c):''
function l(i)print(f(i)+f(N-i/6,f(11-(z=i%6*2),'*')+f(z+1)))
for(i=0;i<N*6;i++)l(i)
for(;i--;)l(i)
Usage: js thisfile.js
JavaScript - In Browser - 154 characters
N=prompt()
function f(n,c){return n>0?(c||' ')+f(n-1,c):''}
s='<pre>'
for(i=0;i<N*6;i++)s+=f(i)+f(N-i/6,f(11-(z=i%6*2),'*')+f(z+1))+'\n'
document.write(s)
The non-obfuscated version (before optimizations by gnarf):
var N = prompt();
var S = ' ';
function fill(c, n) {
for (ret=''; n--;)
ret += c;
return ret;
}
var str = '<pre>';
for (i=0; i<N*6; i++) {
str += fill(S, i);
for (j=0; j<N-i/6; j++)
str += fill('*', 11-i%6*2) + fill(S, i%6*2+1);
str += '\n';
}
document.write(str);
Here's a different algorithm that uses replace() to go from one line to the next of each line of a triangle row:
161 characters
N=readline()
function f(n,c){return n>0?(c||' ')+f(n-1,c):''}l=0
for(i=N;i>0;){r=f(i--,f(11,'*')+' ');for(j=6;j--;){print(f(l++)+r)
r=r.replace(/\*\* /g,' ')}}
F#, 184 181 167 151 147 143 142 133 chars
let N,r=int(stdin.ReadLine()),String.replicate
for l in[0..N*6-1]do printfn"%s%s"(r l" ")(r(N-l/6)((r(11-l%6*2)"*")+(r(l%6*2+1)" ")))
Bonus, 215 212 198 166 162 158 157 148 chars
let N,r=int(stdin.ReadLine()),String.replicate
for l in[0..N*6-1]#[N*6-1..-1..0]do printfn"%s%s"(r l" ")(r(N-l/6)((r(11-l%6*2)"*")+(r(l%6*2+1)" ")))
C - 120 Chars
main(w,i,x,y){w=getchar()%8*12;for(i=0;i<w*w/2;)y=i/w,x=i++%w,putchar(x>w-2?10:x<y|w-x-1<y|(x-y)%12>=11-2*(y%6)?32:42);}
Note that this solution prints some trailing spaces (which is okay, right?). It also relies on relational operators having higher precedence than bitwise OR, saving two characters.
124 Chars
main(n,i,k){n=getchar()&7;for(k=0;k<6*n;k++,putchar(10))for(i=-k-1;++i<12*n-2*k-1;putchar(32+10*(i>=0&&(11-i%12>2*k%12))));}
C - 177 183 Chars
#define P(I,C)for(m=0;m<I;m++)putchar(C)
main(t,c,r,o,m){scanf("%d",&t);for(c=t;c>0;c--)for(r=6;r>0;r--){P((t-c)*6+6-r,32);for(o=0;o<c;o++){P(r*2-1,42);P(13-r*2,32);}puts("");}}
C - 222 243 Chars (With Bonus Points)
#define P(I,C)for(m=0;m<I;m++)putchar(C)
main(t,c,r,o,m){scanf("%d",&t);for(c=t-1;-c<2+t;c-=1+!c)for(r=c<0?1:6;c<0?r<7:r>0;r+=c<0?1:-1){P((t-abs(c+1))*6+6-r,32);for(o=0;o<abs(c+1);o++){P(r*2-1,42);P(13-r*2,32);}puts("");}}
This is my first Code Golf submission as well!
Written in C
Bonus points (492 chars):
p(char *t, int c, int s){int i=0;for(;i<s;i++)printf(" ");for(i=0;i<c;i++)printf("%s",t);printf("\n");}main(int a, char **v){int i=0;int k;int c=atoi(v[1]);for(;i<c;i++){p("*********** ",c-i,i);p(" ********* ",c-i,i);p(" ******* ",c-i,i);p(" ***** ",c-i,i);p(" *** ",c-i,i);p(" * ",c-i,i);}for(i=0;i<c;i++){k=c-i-1;p(" * ",1+i,k);p(" *** ",1+i,k);p(" ***** ",1+i,k);p(" ******* ",1+i,k);p(" ********* ",1+i,k);p("*********** ",i+1,k);}}
Without bonus points (322 chars):
p(char *t, int c, int s){int i=0;for(;i<s;i++)printf(" ");for(i=0;i<c;i++)printf("%s",t);printf("\n");}main(int a, char **v){int i=0;int k;int c=atoi(v[1]);for(;i<c;i++){p("*********** ",c-i,i);p(" ********* ",c-i,i);p(" ******* ",c-i,i);p(" ***** ",c-i,i);p(" *** ",c-i,i);p(" * ",c-i,i);}}
First time posting, too!
Lua, 121 chars
R,N,S=string.rep,io.read'*n',' 'for i=0,N-1 do for j=0,5 do X=R(S,j)print(R(S,6*i)..R(X..R('*',11-2*j)..X..S,N-i))end end
123
R,N,S=string.rep,io.read'*n',' 'for i=0,N-1 do for j=0,5 do print(R(S,6*i)..R(R(S,j)..R('*',11-2*j)..R(S,j)..S,N-i))end end
PHP, 153
<?php $i=fgets(STDIN);function r($n,$c=' '){return$n>0?$c.r($n-1,$c):'';}for($l=0;$l<$i*6;){$z=$l%6*2;echo r($l).r($i-$l++/6,r(11-$z,'*').r($z+1))."\n";}
with Bonus, 210
<?php $i=fgets(STDIN);function r($n,$c=' '){return$n>0?$c.r($n-1,$c):'';}$o=array();for($l=0;$l<$i*6;){$z=$l%6*2;$o[]=r($l).r($i-$l++/6,r(11-$z,'*').r($z+1));}print join("\n",array_merge($o,array_reverse($o)));
dc 105 chars
123 129 132 139 141
[rdPr1-d0<P]sP?sn
0sk[1lk6%2*+sj32lkd0<Plnlk6/-si
[[*]12lj-d0<P32ljd0<Pli1-dsi0<I]dsIx
10Plk1+dskln6*>K]dsKx
Mathematica, 46 characters
The answer prints sideways.
TableForm#{Table["*",{l,#},{l},{j,6},{2j-1}]}&
HyperTalk - 272 chars
function triforce n
put"******" into a
put n*6 into h
repeat with y=0 to h-1
put" " after s
put char 1 to y of s after t
repeat n-y div 6
get y mod 6*2
put char 1 to 11-it of (a&a)&&char 1 to it of s after t
end repeat
put return after t
end repeat
return t
end triforce
Indentation is neither needed nor counted (HyperCard automatically adds it).
Miscellanea:
Since there is no notion of console or way to access console arguments in HyperCard 2.2 (that I know of), a function is given instead. It can be invoked with:
on mouseUp
ask "Triforce: "
put triforce(it) into card field 1
end mouseUp
To use this, a card field would be created and set to a fixed-width font. Using HyperCard's answer command would display a dialog with the text, but it doesn't work because:
The answer dialog font (Chicago) is not fixed-width.
The answer command refuses to display long text (even triforce(2) is too long).
Common Lisp, 150 characters:
(defun f(n o)(unless(= n 0)(dotimes(x 6)(format t"~v#{~a~:*~}~-1:*~v#{~?~2:*~}~%"
o" "n"~11#: "(list(- 11(* 2 x))#\*)))(f(1- n)(+ 6 o))))
77 char alternative python solution based on gnibbler's:
n=input()
k=0
exec"print' '*k+('*'*12+' '*(k%6*2+1))[-12:]*(n-k/6);k+=1;"*6*n
Amazingly the bonus came out exactly the same also (101 chars, oh well)
n=input()
l=1
k=0
s="print' '*k+('*'*12+' '*(k%6*2+1))[-12:]*(n-k/6);k+=l;"*6*n
exec s+'l=-1;k-=1;'+s